Skip to content

Commit

Permalink
c-api: Tidy up some wasmtime_func_t usage (#8461)
Browse files Browse the repository at this point in the history
* c-api: Tidy up some `wasmtime_func_t` usage

Try to avoid using a `transmute` in the implementation of the C API and
instead use a `union` like is being done in #8451. Additionally add some
helper functions to the header to work with null funcref values instead
of only documenting the implementation.

* Try to fix doxygen
  • Loading branch information
alexcrichton authored Apr 24, 2024
1 parent fe67558 commit c6e4a50
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 52 deletions.
62 changes: 33 additions & 29 deletions crates/c-api/include/wasmtime/extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,62 @@ extern "C" {

/// \brief Representation of a function in Wasmtime.
///
/// Functions are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Functions cannot
/// interoperate between #wasmtime_store_t instances and if the wrong function
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
/// Functions in Wasmtime are represented as an index into a store and don't
/// have any data or destructor associated with the #wasmtime_func_t value.
/// Functions cannot interoperate between #wasmtime_store_t instances and if the
/// wrong function is passed to the wrong store then it may trigger an assertion
/// to abort the process.
typedef struct wasmtime_func {
/// Internal identifier of what store this belongs to, never zero.
/// Internal identifier of what store this belongs to.
///
/// This field may be zero when used in conjunction with #wasmtime_val_t
/// to represent a null `funcref` value in WebAssembly. For a valid function
/// this field is otherwise never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
/// Private field for Wasmtime, undefined if `store_id` is zero.
size_t __private;
} wasmtime_func_t;

/// \brief Representation of a table in Wasmtime.
///
/// Tables are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Tables cannot
/// interoperate between #wasmtime_store_t instances and if the wrong table
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
/// Tables in Wasmtime are represented as an index into a store and don't
/// have any data or destructor associated with the #wasmtime_table_t value.
/// Tables cannot interoperate between #wasmtime_store_t instances and if the
/// wrong table is passed to the wrong store then it may trigger an assertion
/// to abort the process.
typedef struct wasmtime_table {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
/// Private field for Wasmtime.
size_t __private;
} wasmtime_table_t;

/// \brief Representation of a memory in Wasmtime.
///
/// Memories are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Memories cannot
/// interoperate between #wasmtime_store_t instances and if the wrong memory
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
/// Memories in Wasmtime are represented as an index into a store and don't
/// have any data or destructor associated with the #wasmtime_memory_t value.
/// Memories cannot interoperate between #wasmtime_store_t instances and if the
/// wrong memory is passed to the wrong store then it may trigger an assertion
/// to abort the process.
typedef struct wasmtime_memory {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
/// Private field for Wasmtime.
size_t __private;
} wasmtime_memory_t;

/// \brief Representation of a global in Wasmtime.
///
/// Globals are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Globals cannot
/// interoperate between #wasmtime_store_t instances and if the wrong global
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
/// Globals in Wasmtime are represented as an index into a store and don't
/// have any data or destructor associated with the #wasmtime_global_t value.
/// Globals cannot interoperate between #wasmtime_store_t instances and if the
/// wrong global is passed to the wrong store then it may trigger an assertion
/// to abort the process.
typedef struct wasmtime_global {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
/// Private field for Wasmtime.
size_t __private;
} wasmtime_global_t;

/// \brief Discriminant of #wasmtime_extern_t
Expand Down
22 changes: 20 additions & 2 deletions crates/c-api/include/wasmtime/val.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,31 @@ typedef union wasmtime_valunion {
wasmtime_externref_t *externref;
/// Field used if #wasmtime_val_t::kind is #WASMTIME_FUNCREF
///
/// If this value represents a `ref.null func` value then the `store_id` field
/// is set to zero.
/// Use `wasmtime_funcref_is_null` to test whether this is a null function
/// reference.
wasmtime_func_t funcref;
/// Field used if #wasmtime_val_t::kind is #WASMTIME_V128
wasmtime_v128 v128;
} wasmtime_valunion_t;

/// \brief Initialize a `wasmtime_func_t` value as a null function reference.
///
/// This function will initialize the `func` provided to be a null function
/// reference. Used in conjunction with #wasmtime_val_t and
/// #wasmtime_valunion_t.
static inline void wasmtime_funcref_set_null(wasmtime_func_t *func) {
func->store_id = 0;
}

/// \brief Helper function to test whether the `func` provided is a null
/// function reference.
///
/// This function is used with #wasmtime_val_t and #wasmtime_valunion_t and its
/// `funcref` field. This will test whether the field represents a null funcref.
static inline bool wasmtime_funcref_is_null(const wasmtime_func_t *func) {
return func->store_id == 0;
}

/**
* \typedef wasmtime_val_raw_t
* \brief Convenience alias for #wasmtime_val_raw
Expand Down
45 changes: 25 additions & 20 deletions crates/c-api/src/val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, wasmtime_anyref_t,
wasmtime_externref_t, wasmtime_valkind_t, WasmtimeStoreContextMut, WASM_I32,
};
use std::mem::{self, ManuallyDrop, MaybeUninit};
use std::mem::{ManuallyDrop, MaybeUninit};
use std::ptr;
use wasmtime::{AsContextMut, Func, HeapType, Ref, RootScope, Val, ValType};

Expand Down Expand Up @@ -171,9 +171,28 @@ where

#[repr(C)]
#[derive(Clone, Copy)]
pub struct wasmtime_func_t {
pub store_id: u64,
pub index: usize,
pub union wasmtime_func_t {
store_id: u64,
func: Func,
}

impl wasmtime_func_t {
unsafe fn as_wasmtime(&self) -> Option<Func> {
if self.store_id == 0 {
None
} else {
Some(self.func)
}
}
}

impl From<Option<Func>> for wasmtime_func_t {
fn from(func: Option<Func>) -> wasmtime_func_t {
match func {
Some(func) => wasmtime_func_t { func },
None => wasmtime_func_t { store_id: 0 },
}
}
}

impl wasmtime_val_t {
Expand Down Expand Up @@ -231,13 +250,7 @@ impl wasmtime_val_t {
Val::FuncRef(func) => wasmtime_val_t {
kind: crate::WASMTIME_FUNCREF,
of: wasmtime_val_union {
funcref: match func {
None => wasmtime_func_t {
store_id: 0,
index: 0,
},
Some(func) => unsafe { mem::transmute::<Func, wasmtime_func_t>(func) },
},
funcref: func.into(),
},
},
Val::V128(val) => wasmtime_val_t {
Expand Down Expand Up @@ -275,15 +288,7 @@ impl wasmtime_val_t {
crate::WASMTIME_EXTERNREF => {
Val::ExternRef(self.of.externref.as_ref().map(|e| e.to_rooted(cx)))
}
crate::WASMTIME_FUNCREF => {
let store = self.of.funcref.store_id;
let index = self.of.funcref.index;
Val::FuncRef(if store == 0 && index == 0 {
None
} else {
Some(mem::transmute::<wasmtime_func_t, Func>(self.of.funcref))
})
}
crate::WASMTIME_FUNCREF => Val::FuncRef(self.of.funcref.as_wasmtime()),
other => panic!("unknown wasmtime_valkind_t: {}", other),
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/runtime/store/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl StoreId {
}
}

#[repr(C)] // used by reference in the C API
#[repr(C)] // used by reference in the C API, also in `wasmtime_func_t`.
pub struct Stored<T> {
store_id: StoreId,
index: usize,
Expand Down

0 comments on commit c6e4a50

Please sign in to comment.