Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support reference types in the C API #1996

Merged
merged 17 commits into from
Jul 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ jobs:

# Ensure all our examples build and execute
- run: cargo run -p run-examples
env:
RUST_BACKTRACE: 1

# Build and test all features except for lightbeam
- run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ rusty-tags.*
tags
target
.z3-trace
foo
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 18 additions & 17 deletions crates/c-api/include/doc-wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1147,19 +1147,22 @@

/**
* \struct wasm_ref_t
* \brief Unimplemented and used in Wasmtime right now.
* \brief A reference type: either a funcref or an externref.
*
* \typedef wasm_ref_t
* \brief Convenience alias for #wasm_ref_t
*
* \fn void wasm_ref_delete(own wasm_ref_t *v);
* \brief Deletes a reference.
* \brief Delete a reference.
*
* \fn own wasm_ref_t *wasm_ref_copy(const wasm_ref_t *)
* \brief Unimplemented in Wasmtime, aborts the process if called.
* \brief Copy a reference.
*
* \fn bool wasm_ref_same(const wasm_ref_t *, const wasm_ref_t *)
* \brief Unimplemented in Wasmtime, aborts the process if called.
* \brief Are the given references pointing to the same externref?
*
* > Note: Wasmtime does not support checking funcrefs for equality, and this
* > function will always return false for funcrefs.
*
* \fn void* wasm_ref_get_host_info(const wasm_ref_t *);
* \brief Unimplemented in Wasmtime, always returns `NULL`.
Expand Down Expand Up @@ -1614,6 +1617,9 @@
* If a trap happens during execution or some other error then a non-`NULL` trap
* is returned. In this situation the `results` are is unmodified.
*
* Does not take ownership of `wasm_val_t` arguments. Gives ownership of
* `wasm_val_t` results.
*
* > Note: to avoid the UB associated with passing the wrong number of results
* > or parameters by accident, or to distinguish between traps and other
* > errors, it's recommended to use #wasmtime_func_call.
Expand Down Expand Up @@ -1758,10 +1764,9 @@
* Returns an error if the #wasm_ref_t does not match the element type of the
* table provided or if it comes from a different store than the one provided.
*
* Does not take ownship of the `init` value.
*
* > Note: for funcref tables you can use #wasmtime_funcref_table_new as well.
* >
* > Additionally the #wasm_ref_t does not have much support in Wasmtime, so you
* > may not be able to create an appropriate initial value.
*
* \fn wasm_tabletype_t *wasm_table_type(const wasm_table_t *);
* \brief Returns the type of this table.
Expand All @@ -1774,12 +1779,10 @@
* Attempts to get a value at an index in this table. This function returns
* `NULL` if the index is out of bounds.
*
* Gives ownership of the resulting `wasm_ref_t*`.
*
* > Note: for funcref tables you can use #wasmtime_funcref_table_get to learn
* > about out-of-bounds errors.
* >
* > Additionally the #wasm_ref_t does not have much
* > support in Wasmtime, so you may not be able to do much with the returned
* > value.
*
* \fn void wasm_table_set(wasm_table_t *, wasm_table_size_t index, wasm_ref_t *);
* \brief Sets an element in this table.
Expand All @@ -1791,11 +1794,10 @@
* * The #wasm_ref_t comes from a different store than the table provided.
* * The #wasm_ref_t does not have an appropriate type to store in this table.
*
* Does not take ownership of the given `wasm_ref_t*`.
*
* > Note: for funcref tables you can use #wasmtime_funcref_table_set to learn
* > about errors.
* >
* > Additionally the #wasm_ref_t does not have much support in Wasmtime, so you
* > may not be able to create an appropriate initial value.
*
* \fn wasm_table_size_t wasm_table_size(const wasm_table_t *);
* \brief Gets the current size, in elements, of this table.
Expand All @@ -1813,10 +1815,9 @@
* * The #wasm_ref_t comes from a different store than the table provided.
* * The #wasm_ref_t does not have an appropriate type to store in this table.
*
* Does not take ownership of the givein `init` value.
*
* > Note: for funcref tables you can use #wasmtime_funcref_table_grow as well.
* >
* > Additionally the #wasm_ref_t does not have much support in Wasmtime, so you
* > may not be able to create an appropriate initial value.
*/

/**
Expand Down
60 changes: 60 additions & 0 deletions crates/c-api/include/wasmtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,9 @@ WASM_API_EXTERN const wasm_name_t *wasmtime_frame_module_name(const wasm_frame_t
*
* The `trap` pointer cannot be `NULL`. The `args` and `results` pointers may be
* `NULL` if the corresponding length is zero.
*
* Does not take ownership of `wasm_val_t` arguments. Gives ownership of
* `wasm_val_t` results.
*/
WASM_API_EXTERN own wasmtime_error_t *wasmtime_func_call(
wasm_func_t *func,
Expand Down Expand Up @@ -833,6 +836,63 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_funcref_table_grow(
wasm_table_size_t *prev_size
);

/**
* \brief Create a new `externref` value.
*
* Creates a new `externref` value wrapping the provided data, and writes it to
* `valp`.
*
* 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 void wasmtime_externref_new(void *data, wasm_val_t *valp);

/**
* \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, and writes it to
* `valp`.
*
* 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 void wasmtime_externref_new_with_finalizer(
void *data,
wasmtime_externref_finalizer_t finalizer,
wasm_val_t *valp
);

/**
* \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

#ifdef __cplusplus
Expand Down
12 changes: 7 additions & 5 deletions crates/c-api/src/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{wasm_extern_t, wasm_functype_t, wasm_store_t, wasm_val_t};
use crate::{wasm_name_t, wasm_trap_t, wasmtime_error_t};
use anyhow::anyhow;
use std::ffi::c_void;
use std::mem::MaybeUninit;
use std::panic::{self, AssertUnwindSafe};
use std::ptr;
use std::str;
Expand Down Expand Up @@ -89,6 +90,7 @@ fn create_function(
let func = Func::new(store, ty, move |caller, params, results| {
let params = params
.iter()
.cloned()
.map(|p| wasm_val_t::from_val(p))
.collect::<Vec<_>>();
let mut out_results = vec![wasm_val_t::default(); results.len()];
Expand Down Expand Up @@ -163,7 +165,7 @@ pub extern "C" fn wasmtime_func_new_with_env(
pub unsafe extern "C" fn wasm_func_call(
wasm_func: &wasm_func_t,
args: *const wasm_val_t,
results: *mut wasm_val_t,
results: *mut MaybeUninit<wasm_val_t>,
) -> *mut wasm_trap_t {
let func = wasm_func.func();
let mut trap = ptr::null_mut();
Expand All @@ -186,7 +188,7 @@ pub unsafe extern "C" fn wasmtime_func_call(
func: &wasm_func_t,
args: *const wasm_val_t,
num_args: usize,
results: *mut wasm_val_t,
results: *mut MaybeUninit<wasm_val_t>,
num_results: usize,
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
Expand All @@ -201,7 +203,7 @@ pub unsafe extern "C" fn wasmtime_func_call(
fn _wasmtime_func_call(
func: &wasm_func_t,
args: &[wasm_val_t],
results: &mut [wasm_val_t],
results: &mut [MaybeUninit<wasm_val_t>],
trap_ptr: &mut *mut wasm_trap_t,
) -> Option<Box<wasmtime_error_t>> {
let func = func.func();
Expand All @@ -217,8 +219,8 @@ fn _wasmtime_func_call(
let result = panic::catch_unwind(AssertUnwindSafe(|| func.call(&params)));
match result {
Ok(Ok(out)) => {
for (slot, val) in results.iter_mut().zip(out.iter()) {
*slot = wasm_val_t::from_val(val);
for (slot, val) in results.iter_mut().zip(out.into_vec().into_iter()) {
crate::initialize(slot, wasm_val_t::from_val(val));
}
None
}
Expand Down
5 changes: 3 additions & 2 deletions crates/c-api/src/global.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{handle_result, wasmtime_error_t};
use crate::{wasm_extern_t, wasm_globaltype_t, wasm_store_t, wasm_val_t};
use std::mem::MaybeUninit;
use std::ptr;
use wasmtime::{Extern, Global};

Expand Down Expand Up @@ -72,8 +73,8 @@ pub extern "C" fn wasm_global_type(g: &wasm_global_t) -> Box<wasm_globaltype_t>
}

#[no_mangle]
pub extern "C" fn wasm_global_get(g: &wasm_global_t, out: &mut wasm_val_t) {
out.set(g.global().get());
pub extern "C" fn wasm_global_get(g: &wasm_global_t, out: &mut MaybeUninit<wasm_val_t>) {
crate::initialize(out, wasm_val_t::from_val(g.global().get()));
}

#[no_mangle]
Expand Down
18 changes: 8 additions & 10 deletions crates/c-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,13 @@ pub struct wasm_shared_module_t {
_unused: [u8; 0],
}

struct HostInfoState {
info: *mut std::ffi::c_void,
finalizer: Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
}

impl Drop for HostInfoState {
fn drop(&mut self) {
if let Some(f) = &self.finalizer {
f(self.info);
}
/// Initialize a `MaybeUninit<T>`
///
/// TODO: Replace calls to this function with
/// https://doc.rust-lang.org/nightly/std/mem/union.MaybeUninit.html#method.write
/// once it is stable.
pub(crate) fn initialize<T>(dst: &mut std::mem::MaybeUninit<T>, val: T) {
unsafe {
std::ptr::write(dst.as_mut_ptr(), val);
}
}
Loading