diff --git a/crates/wasmtime/src/externals.rs b/crates/wasmtime/src/externals.rs
index 2f90384ed77b..c627f38e2040 100644
--- a/crates/wasmtime/src/externals.rs
+++ b/crates/wasmtime/src/externals.rs
@@ -1,13 +1,11 @@
-use crate::store::{StoreData, StoreOpaque, Stored};
-use crate::trampoline::{generate_global_export, generate_table_export};
-use crate::{
- AsContext, AsContextMut, Engine, ExternRef, ExternType, Func, GlobalType, Memory, Mutability,
- SharedMemory, TableType, Val, ValType,
-};
-use anyhow::{anyhow, bail, Result};
-use std::mem;
-use std::ptr;
-use wasmtime_runtime::{self as runtime};
+use crate::store::StoreOpaque;
+use crate::{AsContext, Engine, ExternType, Func, Memory, SharedMemory};
+
+mod global;
+mod table;
+
+pub use global::Global;
+pub use table::Table;
// Externals
@@ -170,583 +168,6 @@ impl From
for Extern {
}
}
-/// A WebAssembly `global` value which can be read and written to.
-///
-/// A `global` in WebAssembly is sort of like a global variable within an
-/// [`Instance`](crate::Instance). The `global.get` and `global.set`
-/// instructions will modify and read global values in a wasm module. Globals
-/// can either be imported or exported from wasm modules.
-///
-/// A [`Global`] "belongs" to the store that it was originally created within
-/// (either via [`Global::new`] or via instantiating a
-/// [`Module`](crate::Module)). Operations on a [`Global`] only work with the
-/// store it belongs to, and if another store is passed in by accident then
-/// methods will panic.
-#[derive(Copy, Clone, Debug)]
-#[repr(transparent)] // here for the C API
-pub struct Global(Stored);
-
-impl Global {
- /// Creates a new WebAssembly `global` value with the provide type `ty` and
- /// initial value `val`.
- ///
- /// The `store` argument will be the owner of the [`Global`] returned. Using
- /// the returned [`Global`] other items in the store may access this global.
- /// For example this could be provided as an argument to
- /// [`Instance::new`](crate::Instance::new) or
- /// [`Linker::define`](crate::Linker::define).
- ///
- /// # Errors
- ///
- /// Returns an error if the `ty` provided does not match the type of the
- /// value `val`, or if `val` comes from a different store than `store`.
- ///
- /// # Examples
- ///
- /// ```
- /// # use wasmtime::*;
- /// # fn main() -> anyhow::Result<()> {
- /// let engine = Engine::default();
- /// let mut store = Store::new(&engine, ());
- ///
- /// let ty = GlobalType::new(ValType::I32, Mutability::Const);
- /// let i32_const = Global::new(&mut store, ty, 1i32.into())?;
- /// let ty = GlobalType::new(ValType::F64, Mutability::Var);
- /// let f64_mut = Global::new(&mut store, ty, 2.0f64.into())?;
- ///
- /// let module = Module::new(
- /// &engine,
- /// "(module
- /// (global (import \"\" \"i32-const\") i32)
- /// (global (import \"\" \"f64-mut\") (mut f64))
- /// )"
- /// )?;
- ///
- /// let mut linker = Linker::new(&engine);
- /// linker.define(&store, "", "i32-const", i32_const)?;
- /// linker.define(&store, "", "f64-mut", f64_mut)?;
- ///
- /// let instance = linker.instantiate(&mut store, &module)?;
- /// // ...
- /// # Ok(())
- /// # }
- /// ```
- pub fn new(mut store: impl AsContextMut, ty: GlobalType, val: Val) -> Result {
- Global::_new(store.as_context_mut().0, ty, val)
- }
-
- fn _new(store: &mut StoreOpaque, ty: GlobalType, val: Val) -> Result {
- if !val.comes_from_same_store(store) {
- bail!("cross-`Store` globals are not supported");
- }
- if val.ty() != *ty.content() {
- bail!("value provided does not match the type of this global");
- }
- unsafe {
- let wasmtime_export = generate_global_export(store, ty, val);
- Ok(Global::from_wasmtime_global(wasmtime_export, store))
- }
- }
-
- /// Returns the underlying type of this `global`.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own this global.
- pub fn ty(&self, store: impl AsContext) -> GlobalType {
- let store = store.as_context();
- let ty = &store[self.0].global;
- GlobalType::from_wasmtime_global(&ty)
- }
-
- /// Returns the current [`Val`] of this global.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own this global.
- pub fn get(&self, mut store: impl AsContextMut) -> Val {
- unsafe {
- let store = store.as_context_mut();
- let definition = &*store[self.0].definition;
- match self.ty(&store).content() {
- ValType::I32 => Val::from(*definition.as_i32()),
- ValType::I64 => Val::from(*definition.as_i64()),
- ValType::F32 => Val::F32(*definition.as_u32()),
- ValType::F64 => Val::F64(*definition.as_u64()),
- ValType::ExternRef => Val::ExternRef(
- definition
- .as_externref()
- .clone()
- .map(|inner| ExternRef { inner }),
- ),
- ValType::FuncRef => {
- Val::FuncRef(Func::from_raw(store, definition.as_func_ref().cast()))
- }
- ValType::V128 => Val::V128((*definition.as_u128()).into()),
- }
- }
- }
-
- /// Attempts to set the current value of this global to [`Val`].
- ///
- /// # Errors
- ///
- /// Returns an error if this global has a different type than `Val`, if
- /// it's not a mutable global, or if `val` comes from a different store than
- /// the one provided.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own this global.
- pub fn set(&self, mut store: impl AsContextMut, val: Val) -> Result<()> {
- let store = store.as_context_mut().0;
- let ty = self.ty(&store);
- if ty.mutability() != Mutability::Var {
- bail!("immutable global cannot be set");
- }
- let ty = ty.content();
- if val.ty() != *ty {
- bail!("global of type {:?} cannot be set to {:?}", ty, val.ty());
- }
- if !val.comes_from_same_store(store) {
- bail!("cross-`Store` values are not supported");
- }
- unsafe {
- let definition = &mut *store[self.0].definition;
- match val {
- Val::I32(i) => *definition.as_i32_mut() = i,
- Val::I64(i) => *definition.as_i64_mut() = i,
- Val::F32(f) => *definition.as_u32_mut() = f,
- Val::F64(f) => *definition.as_u64_mut() = f,
- Val::FuncRef(f) => {
- *definition.as_func_ref_mut() = f.map_or(ptr::null_mut(), |f| {
- f.caller_checked_func_ref(store).as_ptr().cast()
- });
- }
- Val::ExternRef(x) => {
- let old = mem::replace(definition.as_externref_mut(), x.map(|x| x.inner));
- drop(old);
- }
- Val::V128(i) => *definition.as_u128_mut() = i.into(),
- }
- }
- Ok(())
- }
-
- pub(crate) unsafe fn from_wasmtime_global(
- wasmtime_export: wasmtime_runtime::ExportGlobal,
- store: &mut StoreOpaque,
- ) -> Global {
- Global(store.store_data_mut().insert(wasmtime_export))
- }
-
- pub(crate) fn wasmtime_ty<'a>(&self, data: &'a StoreData) -> &'a wasmtime_environ::Global {
- &data[self.0].global
- }
-
- pub(crate) fn vmimport(&self, store: &StoreOpaque) -> wasmtime_runtime::VMGlobalImport {
- wasmtime_runtime::VMGlobalImport {
- from: store[self.0].definition,
- }
- }
-
- /// Get a stable hash key for this global.
- ///
- /// Even if the same underlying global definition is added to the
- /// `StoreData` multiple times and becomes multiple `wasmtime::Global`s,
- /// this hash key will be consistent across all of these globals.
- pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl std::hash::Hash + Eq {
- store[self.0].definition as usize
- }
-}
-
-#[cfg(test)]
-mod global_tests {
- use super::*;
- use crate::{Instance, Module, Store};
-
- #[test]
- fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
- let mut store = Store::<()>::default();
- let module = Module::new(
- store.engine(),
- r#"
- (module
- (global (export "g") (mut i32) (i32.const 0))
- )
- "#,
- )?;
- let instance = Instance::new(&mut store, &module, &[])?;
-
- // Each time we `get_global`, we call `Global::from_wasmtime` which adds
- // a new entry to `StoreData`, so `g1` and `g2` will have different
- // indices into `StoreData`.
- let g1 = instance.get_global(&mut store, "g").unwrap();
- let g2 = instance.get_global(&mut store, "g").unwrap();
-
- // That said, they really point to the same global.
- assert_eq!(g1.get(&mut store).unwrap_i32(), 0);
- assert_eq!(g2.get(&mut store).unwrap_i32(), 0);
- g1.set(&mut store, Val::I32(42))?;
- assert_eq!(g1.get(&mut store).unwrap_i32(), 42);
- assert_eq!(g2.get(&mut store).unwrap_i32(), 42);
-
- // And therefore their hash keys are the same.
- assert!(g1.hash_key(&store.as_context().0) == g2.hash_key(&store.as_context().0));
-
- // But the hash keys are different from different globals.
- let instance2 = Instance::new(&mut store, &module, &[])?;
- let g3 = instance2.get_global(&mut store, "g").unwrap();
- assert!(g1.hash_key(&store.as_context().0) != g3.hash_key(&store.as_context().0));
-
- Ok(())
- }
-}
-
-/// A WebAssembly `table`, or an array of values.
-///
-/// Like [`Memory`] a table is an indexed array of values, but unlike [`Memory`]
-/// it's an array of WebAssembly reference type values rather than bytes. One of
-/// the most common usages of a table is a function table for wasm modules (a
-/// `funcref` table), where each element has the `ValType::FuncRef` type.
-///
-/// A [`Table`] "belongs" to the store that it was originally created within
-/// (either via [`Table::new`] or via instantiating a
-/// [`Module`](crate::Module)). Operations on a [`Table`] only work with the
-/// store it belongs to, and if another store is passed in by accident then
-/// methods will panic.
-#[derive(Copy, Clone, Debug)]
-#[repr(transparent)] // here for the C API
-pub struct Table(Stored);
-
-impl Table {
- /// Creates a new [`Table`] with the given parameters.
- ///
- /// * `store` - the owner of the resulting [`Table`]
- /// * `ty` - the type of this table, containing both the element type as
- /// well as the initial size and maximum size, if any.
- /// * `init` - the initial value to fill all table entries with, if the
- /// table starts with an initial size.
- ///
- /// # Errors
- ///
- /// Returns an error if `init` does not match the element type of the table,
- /// or if `init` does not belong to the `store` provided.
- ///
- /// # Panics
- ///
- /// This function will panic when used with a [`Store`](`crate::Store`)
- /// which has a [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`)
- /// (see also: [`Store::limiter_async`](`crate::Store::limiter_async`).
- /// When using an async resource limiter, use [`Table::new_async`]
- /// instead.
- ///
- /// # Examples
- ///
- /// ```
- /// # use wasmtime::*;
- /// # fn main() -> anyhow::Result<()> {
- /// let engine = Engine::default();
- /// let mut store = Store::new(&engine, ());
- ///
- /// let ty = TableType::new(ValType::FuncRef, 2, None);
- /// let table = Table::new(&mut store, ty, Val::FuncRef(None))?;
- ///
- /// let module = Module::new(
- /// &engine,
- /// "(module
- /// (table (import \"\" \"\") 2 funcref)
- /// (func $f (result i32)
- /// i32.const 10)
- /// (elem (i32.const 0) $f)
- /// )"
- /// )?;
- ///
- /// let instance = Instance::new(&mut store, &module, &[table.into()])?;
- /// // ...
- /// # Ok(())
- /// # }
- /// ```
- pub fn new(mut store: impl AsContextMut, ty: TableType, init: Val) -> Result {
- Table::_new(store.as_context_mut().0, ty, init)
- }
-
- #[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
- /// Async variant of [`Table::new`]. You must use this variant with
- /// [`Store`](`crate::Store`)s which have a
- /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`).
- ///
- /// # Panics
- ///
- /// This function will panic when used with a non-async
- /// [`Store`](`crate::Store`)
- #[cfg(feature = "async")]
- pub async fn new_async(
- mut store: impl AsContextMut,
- ty: TableType,
- init: Val,
- ) -> Result
- where
- T: Send,
- {
- let mut store = store.as_context_mut();
- assert!(
- store.0.async_support(),
- "cannot use `new_async` without enabling async support on the config"
- );
- store
- .on_fiber(|store| Table::_new(store.0, ty, init))
- .await?
- }
-
- fn _new(store: &mut StoreOpaque, ty: TableType, init: Val) -> Result {
- let wasmtime_export = generate_table_export(store, &ty)?;
- let init = init.into_table_element(store, ty.element())?;
- unsafe {
- let table = Table::from_wasmtime_table(wasmtime_export, store);
- (*table.wasmtime_table(store, std::iter::empty())).fill(0, init, ty.minimum())?;
-
- Ok(table)
- }
- }
-
- /// Returns the underlying type of this table, including its element type as
- /// well as the maximum/minimum lower bounds.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own this table.
- pub fn ty(&self, store: impl AsContext) -> TableType {
- let store = store.as_context();
- let ty = &store[self.0].table.table;
- TableType::from_wasmtime_table(ty)
- }
-
- fn wasmtime_table(
- &self,
- store: &mut StoreOpaque,
- lazy_init_range: impl Iterator- ,
- ) -> *mut runtime::Table {
- unsafe {
- let export = &store[self.0];
- wasmtime_runtime::Instance::from_vmctx(export.vmctx, |handle| {
- let idx = handle.table_index(&*export.definition);
- handle.get_defined_table_with_lazy_init(idx, lazy_init_range)
- })
- }
- }
-
- /// Returns the table element value at `index`.
- ///
- /// Returns `None` if `index` is out of bounds.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own this table.
- pub fn get(&self, mut store: impl AsContextMut, index: u32) -> Option {
- let store = store.as_context_mut().0;
- let table = self.wasmtime_table(store, std::iter::once(index));
- unsafe {
- match (*table).get(index)? {
- runtime::TableElement::FuncRef(f) => {
- let func = Func::from_caller_checked_func_ref(store, f);
- Some(Val::FuncRef(func))
- }
- runtime::TableElement::ExternRef(None) => Some(Val::ExternRef(None)),
- runtime::TableElement::ExternRef(Some(x)) => {
- Some(Val::ExternRef(Some(ExternRef { inner: x })))
- }
- runtime::TableElement::UninitFunc => {
- unreachable!("lazy init above should have converted UninitFunc")
- }
- }
- }
- }
-
- /// Writes the `val` provided into `index` within this table.
- ///
- /// # Errors
- ///
- /// Returns an error if `index` is out of bounds, if `val` does not have
- /// the right type to be stored in this table, or if `val` belongs to a
- /// different store.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own this table.
- pub fn set(&self, mut store: impl AsContextMut, index: u32, val: Val) -> Result<()> {
- let store = store.as_context_mut().0;
- let ty = self.ty(&store).element().clone();
- let val = val.into_table_element(store, ty)?;
- let table = self.wasmtime_table(store, std::iter::empty());
- unsafe {
- (*table)
- .set(index, val)
- .map_err(|()| anyhow!("table element index out of bounds"))
- }
- }
-
- /// Returns the current size of this table.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own this table.
- pub fn size(&self, store: impl AsContext) -> u32 {
- self.internal_size(store.as_context().0)
- }
-
- pub(crate) fn internal_size(&self, store: &StoreOpaque) -> u32 {
- unsafe { (*store[self.0].definition).current_elements }
- }
-
- /// Grows the size of this table by `delta` more elements, initialization
- /// all new elements to `init`.
- ///
- /// Returns the previous size of this table if successful.
- ///
- /// # Errors
- ///
- /// Returns an error if the table cannot be grown by `delta`, for example
- /// if it would cause the table to exceed its maximum size. Also returns an
- /// error if `init` is not of the right type or if `init` does not belong to
- /// `store`.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own this table.
- ///
- /// This function will panic when used with a [`Store`](`crate::Store`)
- /// which has a [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`)
- /// (see also: [`Store::limiter_async`](`crate::Store::limiter_async`)).
- /// When using an async resource limiter, use [`Table::grow_async`]
- /// instead.
- pub fn grow(&self, mut store: impl AsContextMut, delta: u32, init: Val) -> Result {
- let store = store.as_context_mut().0;
- let ty = self.ty(&store).element().clone();
- let init = init.into_table_element(store, ty)?;
- let table = self.wasmtime_table(store, std::iter::empty());
- unsafe {
- match (*table).grow(delta, init, store)? {
- Some(size) => {
- let vm = (*table).vmtable();
- *store[self.0].definition = vm;
- Ok(size)
- }
- None => bail!("failed to grow table by `{}`", delta),
- }
- }
- }
-
- #[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
- /// Async variant of [`Table::grow`]. Required when using a
- /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`).
- ///
- /// # Panics
- ///
- /// This function will panic when used with a non-async
- /// [`Store`](`crate::Store`).
- #[cfg(feature = "async")]
- pub async fn grow_async(
- &self,
- mut store: impl AsContextMut,
- delta: u32,
- init: Val,
- ) -> Result
- where
- T: Send,
- {
- let mut store = store.as_context_mut();
- assert!(
- store.0.async_support(),
- "cannot use `grow_async` without enabling async support on the config"
- );
- store
- .on_fiber(|store| self.grow(store, delta, init))
- .await?
- }
-
- /// Copy `len` elements from `src_table[src_index..]` into
- /// `dst_table[dst_index..]`.
- ///
- /// # Errors
- ///
- /// Returns an error if the range is out of bounds of either the source or
- /// destination tables.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own either `dst_table` or `src_table`.
- pub fn copy(
- mut store: impl AsContextMut,
- dst_table: &Table,
- dst_index: u32,
- src_table: &Table,
- src_index: u32,
- len: u32,
- ) -> Result<()> {
- let store = store.as_context_mut().0;
- if dst_table.ty(&store).element() != src_table.ty(&store).element() {
- bail!("tables do not have the same element type");
- }
-
- let dst_table = dst_table.wasmtime_table(store, std::iter::empty());
- let src_range = src_index..(src_index.checked_add(len).unwrap_or(u32::MAX));
- let src_table = src_table.wasmtime_table(store, src_range);
- unsafe {
- runtime::Table::copy(dst_table, src_table, dst_index, src_index, len)?;
- }
- Ok(())
- }
-
- /// Fill `table[dst..(dst + len)]` with the given value.
- ///
- /// # Errors
- ///
- /// Returns an error if
- ///
- /// * `val` is not of the same type as this table's
- /// element type,
- ///
- /// * the region to be filled is out of bounds, or
- ///
- /// * `val` comes from a different `Store` from this table.
- ///
- /// # Panics
- ///
- /// Panics if `store` does not own either `dst_table` or `src_table`.
- pub fn fill(&self, mut store: impl AsContextMut, dst: u32, val: Val, len: u32) -> Result<()> {
- let store = store.as_context_mut().0;
- let ty = self.ty(&store).element().clone();
- let val = val.into_table_element(store, ty)?;
-
- let table = self.wasmtime_table(store, std::iter::empty());
- unsafe {
- (*table).fill(dst, val, len)?;
- }
-
- Ok(())
- }
-
- pub(crate) unsafe fn from_wasmtime_table(
- wasmtime_export: wasmtime_runtime::ExportTable,
- store: &mut StoreOpaque,
- ) -> Table {
- Table(store.store_data_mut().insert(wasmtime_export))
- }
-
- pub(crate) fn wasmtime_ty<'a>(&self, data: &'a StoreData) -> &'a wasmtime_environ::Table {
- &data[self.0].table.table
- }
-
- pub(crate) fn vmimport(&self, store: &StoreOpaque) -> wasmtime_runtime::VMTableImport {
- let export = &store[self.0];
- wasmtime_runtime::VMTableImport {
- from: export.definition,
- vmctx: export.vmctx,
- }
- }
-}
-
// Exports
/// An exported WebAssembly value.
diff --git a/crates/wasmtime/src/externals/global.rs b/crates/wasmtime/src/externals/global.rs
new file mode 100644
index 000000000000..fb089ba9f52b
--- /dev/null
+++ b/crates/wasmtime/src/externals/global.rs
@@ -0,0 +1,238 @@
+use crate::store::{StoreData, StoreOpaque, Stored};
+use crate::trampoline::generate_global_export;
+use crate::{AsContext, AsContextMut, ExternRef, Func, GlobalType, Mutability, Val, ValType};
+use anyhow::{bail, Result};
+use std::mem;
+use std::ptr;
+
+/// A WebAssembly `global` value which can be read and written to.
+///
+/// A `global` in WebAssembly is sort of like a global variable within an
+/// [`Instance`](crate::Instance). The `global.get` and `global.set`
+/// instructions will modify and read global values in a wasm module. Globals
+/// can either be imported or exported from wasm modules.
+///
+/// A [`Global`] "belongs" to the store that it was originally created within
+/// (either via [`Global::new`] or via instantiating a
+/// [`Module`](crate::Module)). Operations on a [`Global`] only work with the
+/// store it belongs to, and if another store is passed in by accident then
+/// methods will panic.
+#[derive(Copy, Clone, Debug)]
+#[repr(transparent)] // here for the C API
+pub struct Global(pub(super) Stored);
+
+impl Global {
+ /// Creates a new WebAssembly `global` value with the provide type `ty` and
+ /// initial value `val`.
+ ///
+ /// The `store` argument will be the owner of the [`Global`] returned. Using
+ /// the returned [`Global`] other items in the store may access this global.
+ /// For example this could be provided as an argument to
+ /// [`Instance::new`](crate::Instance::new) or
+ /// [`Linker::define`](crate::Linker::define).
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the `ty` provided does not match the type of the
+ /// value `val`, or if `val` comes from a different store than `store`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use wasmtime::*;
+ /// # fn main() -> anyhow::Result<()> {
+ /// let engine = Engine::default();
+ /// let mut store = Store::new(&engine, ());
+ ///
+ /// let ty = GlobalType::new(ValType::I32, Mutability::Const);
+ /// let i32_const = Global::new(&mut store, ty, 1i32.into())?;
+ /// let ty = GlobalType::new(ValType::F64, Mutability::Var);
+ /// let f64_mut = Global::new(&mut store, ty, 2.0f64.into())?;
+ ///
+ /// let module = Module::new(
+ /// &engine,
+ /// "(module
+ /// (global (import \"\" \"i32-const\") i32)
+ /// (global (import \"\" \"f64-mut\") (mut f64))
+ /// )"
+ /// )?;
+ ///
+ /// let mut linker = Linker::new(&engine);
+ /// linker.define(&store, "", "i32-const", i32_const)?;
+ /// linker.define(&store, "", "f64-mut", f64_mut)?;
+ ///
+ /// let instance = linker.instantiate(&mut store, &module)?;
+ /// // ...
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn new(mut store: impl AsContextMut, ty: GlobalType, val: Val) -> Result {
+ Global::_new(store.as_context_mut().0, ty, val)
+ }
+
+ fn _new(store: &mut StoreOpaque, ty: GlobalType, val: Val) -> Result {
+ if !val.comes_from_same_store(store) {
+ bail!("cross-`Store` globals are not supported");
+ }
+ if val.ty() != *ty.content() {
+ bail!("value provided does not match the type of this global");
+ }
+ unsafe {
+ let wasmtime_export = generate_global_export(store, ty, val);
+ Ok(Global::from_wasmtime_global(wasmtime_export, store))
+ }
+ }
+
+ /// Returns the underlying type of this `global`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own this global.
+ pub fn ty(&self, store: impl AsContext) -> GlobalType {
+ let store = store.as_context();
+ let ty = &store[self.0].global;
+ GlobalType::from_wasmtime_global(&ty)
+ }
+
+ /// Returns the current [`Val`] of this global.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own this global.
+ pub fn get(&self, mut store: impl AsContextMut) -> Val {
+ unsafe {
+ let store = store.as_context_mut();
+ let definition = &*store[self.0].definition;
+ match self.ty(&store).content() {
+ ValType::I32 => Val::from(*definition.as_i32()),
+ ValType::I64 => Val::from(*definition.as_i64()),
+ ValType::F32 => Val::F32(*definition.as_u32()),
+ ValType::F64 => Val::F64(*definition.as_u64()),
+ ValType::ExternRef => Val::ExternRef(
+ definition
+ .as_externref()
+ .clone()
+ .map(|inner| ExternRef { inner }),
+ ),
+ ValType::FuncRef => {
+ Val::FuncRef(Func::from_raw(store, definition.as_func_ref().cast()))
+ }
+ ValType::V128 => Val::V128((*definition.as_u128()).into()),
+ }
+ }
+ }
+
+ /// Attempts to set the current value of this global to [`Val`].
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if this global has a different type than `Val`, if
+ /// it's not a mutable global, or if `val` comes from a different store than
+ /// the one provided.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own this global.
+ pub fn set(&self, mut store: impl AsContextMut, val: Val) -> Result<()> {
+ let store = store.as_context_mut().0;
+ let ty = self.ty(&store);
+ if ty.mutability() != Mutability::Var {
+ bail!("immutable global cannot be set");
+ }
+ let ty = ty.content();
+ if val.ty() != *ty {
+ bail!("global of type {:?} cannot be set to {:?}", ty, val.ty());
+ }
+ if !val.comes_from_same_store(store) {
+ bail!("cross-`Store` values are not supported");
+ }
+ unsafe {
+ let definition = &mut *store[self.0].definition;
+ match val {
+ Val::I32(i) => *definition.as_i32_mut() = i,
+ Val::I64(i) => *definition.as_i64_mut() = i,
+ Val::F32(f) => *definition.as_u32_mut() = f,
+ Val::F64(f) => *definition.as_u64_mut() = f,
+ Val::FuncRef(f) => {
+ *definition.as_func_ref_mut() =
+ f.map_or(ptr::null_mut(), |f| f.vm_func_ref(store).as_ptr().cast());
+ }
+ Val::ExternRef(x) => {
+ let old = mem::replace(definition.as_externref_mut(), x.map(|x| x.inner));
+ drop(old);
+ }
+ Val::V128(i) => *definition.as_u128_mut() = i.into(),
+ }
+ }
+ Ok(())
+ }
+
+ pub(crate) unsafe fn from_wasmtime_global(
+ wasmtime_export: wasmtime_runtime::ExportGlobal,
+ store: &mut StoreOpaque,
+ ) -> Global {
+ Global(store.store_data_mut().insert(wasmtime_export))
+ }
+
+ pub(crate) fn wasmtime_ty<'a>(&self, data: &'a StoreData) -> &'a wasmtime_environ::Global {
+ &data[self.0].global
+ }
+
+ pub(crate) fn vmimport(&self, store: &StoreOpaque) -> wasmtime_runtime::VMGlobalImport {
+ wasmtime_runtime::VMGlobalImport {
+ from: store[self.0].definition,
+ }
+ }
+
+ /// Get a stable hash key for this global.
+ ///
+ /// Even if the same underlying global definition is added to the
+ /// `StoreData` multiple times and becomes multiple `wasmtime::Global`s,
+ /// this hash key will be consistent across all of these globals.
+ pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl std::hash::Hash + Eq {
+ store[self.0].definition as usize
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{Instance, Module, Store};
+
+ #[test]
+ fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
+ let mut store = Store::<()>::default();
+ let module = Module::new(
+ store.engine(),
+ r#"
+ (module
+ (global (export "g") (mut i32) (i32.const 0))
+ )
+ "#,
+ )?;
+ let instance = Instance::new(&mut store, &module, &[])?;
+
+ // Each time we `get_global`, we call `Global::from_wasmtime` which adds
+ // a new entry to `StoreData`, so `g1` and `g2` will have different
+ // indices into `StoreData`.
+ let g1 = instance.get_global(&mut store, "g").unwrap();
+ let g2 = instance.get_global(&mut store, "g").unwrap();
+
+ // That said, they really point to the same global.
+ assert_eq!(g1.get(&mut store).unwrap_i32(), 0);
+ assert_eq!(g2.get(&mut store).unwrap_i32(), 0);
+ g1.set(&mut store, Val::I32(42))?;
+ assert_eq!(g1.get(&mut store).unwrap_i32(), 42);
+ assert_eq!(g2.get(&mut store).unwrap_i32(), 42);
+
+ // And therefore their hash keys are the same.
+ assert!(g1.hash_key(&store.as_context().0) == g2.hash_key(&store.as_context().0));
+
+ // But the hash keys are different from different globals.
+ let instance2 = Instance::new(&mut store, &module, &[])?;
+ let g3 = instance2.get_global(&mut store, "g").unwrap();
+ assert!(g1.hash_key(&store.as_context().0) != g3.hash_key(&store.as_context().0));
+
+ Ok(())
+ }
+}
diff --git a/crates/wasmtime/src/externals/table.rs b/crates/wasmtime/src/externals/table.rs
new file mode 100644
index 000000000000..cbd688207d5d
--- /dev/null
+++ b/crates/wasmtime/src/externals/table.rs
@@ -0,0 +1,403 @@
+use crate::store::{StoreData, StoreOpaque, Stored};
+use crate::trampoline::generate_table_export;
+use crate::{AsContext, AsContextMut, ExternRef, Func, TableType, Val};
+use anyhow::{anyhow, bail, Result};
+use wasmtime_runtime::{self as runtime};
+
+/// A WebAssembly `table`, or an array of values.
+///
+/// Like [`Memory`][crate::Memory] a table is an indexed array of values, but
+/// unlike [`Memory`][crate::Memory] it's an array of WebAssembly reference type
+/// values rather than bytes. One of the most common usages of a table is a
+/// function table for wasm modules (a `funcref` table), where each element has
+/// the `ValType::FuncRef` type.
+///
+/// A [`Table`] "belongs" to the store that it was originally created within
+/// (either via [`Table::new`] or via instantiating a
+/// [`Module`](crate::Module)). Operations on a [`Table`] only work with the
+/// store it belongs to, and if another store is passed in by accident then
+/// methods will panic.
+#[derive(Copy, Clone, Debug)]
+#[repr(transparent)] // here for the C API
+pub struct Table(pub(super) Stored);
+
+impl Table {
+ /// Creates a new [`Table`] with the given parameters.
+ ///
+ /// * `store` - the owner of the resulting [`Table`]
+ /// * `ty` - the type of this table, containing both the element type as
+ /// well as the initial size and maximum size, if any.
+ /// * `init` - the initial value to fill all table entries with, if the
+ /// table starts with an initial size.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if `init` does not match the element type of the table,
+ /// or if `init` does not belong to the `store` provided.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic when used with a [`Store`](`crate::Store`)
+ /// which has a [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`)
+ /// (see also: [`Store::limiter_async`](`crate::Store::limiter_async`).
+ /// When using an async resource limiter, use [`Table::new_async`]
+ /// instead.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use wasmtime::*;
+ /// # fn main() -> anyhow::Result<()> {
+ /// let engine = Engine::default();
+ /// let mut store = Store::new(&engine, ());
+ ///
+ /// let ty = TableType::new(ValType::FuncRef, 2, None);
+ /// let table = Table::new(&mut store, ty, Val::FuncRef(None))?;
+ ///
+ /// let module = Module::new(
+ /// &engine,
+ /// "(module
+ /// (table (import \"\" \"\") 2 funcref)
+ /// (func $f (result i32)
+ /// i32.const 10)
+ /// (elem (i32.const 0) $f)
+ /// )"
+ /// )?;
+ ///
+ /// let instance = Instance::new(&mut store, &module, &[table.into()])?;
+ /// // ...
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn new(mut store: impl AsContextMut, ty: TableType, init: Val) -> Result
{
+ Table::_new(store.as_context_mut().0, ty, init)
+ }
+
+ #[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
+ /// Async variant of [`Table::new`]. You must use this variant with
+ /// [`Store`](`crate::Store`)s which have a
+ /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`).
+ ///
+ /// # Panics
+ ///
+ /// This function will panic when used with a non-async
+ /// [`Store`](`crate::Store`)
+ #[cfg(feature = "async")]
+ pub async fn new_async(
+ mut store: impl AsContextMut,
+ ty: TableType,
+ init: Val,
+ ) -> Result
+ where
+ T: Send,
+ {
+ let mut store = store.as_context_mut();
+ assert!(
+ store.0.async_support(),
+ "cannot use `new_async` without enabling async support on the config"
+ );
+ store
+ .on_fiber(|store| Table::_new(store.0, ty, init))
+ .await?
+ }
+
+ fn _new(store: &mut StoreOpaque, ty: TableType, init: Val) -> Result {
+ let wasmtime_export = generate_table_export(store, &ty)?;
+ let init = init.into_table_element(store, ty.element())?;
+ unsafe {
+ let table = Table::from_wasmtime_table(wasmtime_export, store);
+ (*table.wasmtime_table(store, std::iter::empty())).fill(0, init, ty.minimum())?;
+
+ Ok(table)
+ }
+ }
+
+ /// Returns the underlying type of this table, including its element type as
+ /// well as the maximum/minimum lower bounds.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own this table.
+ pub fn ty(&self, store: impl AsContext) -> TableType {
+ let store = store.as_context();
+ let ty = &store[self.0].table.table;
+ TableType::from_wasmtime_table(ty)
+ }
+
+ fn wasmtime_table(
+ &self,
+ store: &mut StoreOpaque,
+ lazy_init_range: impl Iterator- ,
+ ) -> *mut runtime::Table {
+ unsafe {
+ let export = &store[self.0];
+ wasmtime_runtime::Instance::from_vmctx(export.vmctx, |handle| {
+ let idx = handle.table_index(&*export.definition);
+ handle.get_defined_table_with_lazy_init(idx, lazy_init_range)
+ })
+ }
+ }
+
+ /// Returns the table element value at `index`.
+ ///
+ /// Returns `None` if `index` is out of bounds.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own this table.
+ pub fn get(&self, mut store: impl AsContextMut, index: u32) -> Option {
+ let store = store.as_context_mut().0;
+ let table = self.wasmtime_table(store, std::iter::once(index));
+ unsafe {
+ match (*table).get(index)? {
+ runtime::TableElement::FuncRef(f) => {
+ let func = Func::from_caller_checked_func_ref(store, f);
+ Some(Val::FuncRef(func))
+ }
+ runtime::TableElement::ExternRef(None) => Some(Val::ExternRef(None)),
+ runtime::TableElement::ExternRef(Some(x)) => {
+ Some(Val::ExternRef(Some(ExternRef { inner: x })))
+ }
+ runtime::TableElement::UninitFunc => {
+ unreachable!("lazy init above should have converted UninitFunc")
+ }
+ }
+ }
+ }
+
+ /// Writes the `val` provided into `index` within this table.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if `index` is out of bounds, if `val` does not have
+ /// the right type to be stored in this table, or if `val` belongs to a
+ /// different store.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own this table.
+ pub fn set(&self, mut store: impl AsContextMut, index: u32, val: Val) -> Result<()> {
+ let store = store.as_context_mut().0;
+ let ty = self.ty(&store).element().clone();
+ let val = val.into_table_element(store, ty)?;
+ let table = self.wasmtime_table(store, std::iter::empty());
+ unsafe {
+ (*table)
+ .set(index, val)
+ .map_err(|()| anyhow!("table element index out of bounds"))
+ }
+ }
+
+ /// Returns the current size of this table.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own this table.
+ pub fn size(&self, store: impl AsContext) -> u32 {
+ self.internal_size(store.as_context().0)
+ }
+
+ pub(crate) fn internal_size(&self, store: &StoreOpaque) -> u32 {
+ unsafe { (*store[self.0].definition).current_elements }
+ }
+
+ /// Grows the size of this table by `delta` more elements, initialization
+ /// all new elements to `init`.
+ ///
+ /// Returns the previous size of this table if successful.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the table cannot be grown by `delta`, for example
+ /// if it would cause the table to exceed its maximum size. Also returns an
+ /// error if `init` is not of the right type or if `init` does not belong to
+ /// `store`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own this table.
+ ///
+ /// This function will panic when used with a [`Store`](`crate::Store`)
+ /// which has a [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`)
+ /// (see also: [`Store::limiter_async`](`crate::Store::limiter_async`)).
+ /// When using an async resource limiter, use [`Table::grow_async`]
+ /// instead.
+ pub fn grow(&self, mut store: impl AsContextMut, delta: u32, init: Val) -> Result {
+ let store = store.as_context_mut().0;
+ let ty = self.ty(&store).element().clone();
+ let init = init.into_table_element(store, ty)?;
+ let table = self.wasmtime_table(store, std::iter::empty());
+ unsafe {
+ match (*table).grow(delta, init, store)? {
+ Some(size) => {
+ let vm = (*table).vmtable();
+ *store[self.0].definition = vm;
+ Ok(size)
+ }
+ None => bail!("failed to grow table by `{}`", delta),
+ }
+ }
+ }
+
+ #[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
+ /// Async variant of [`Table::grow`]. Required when using a
+ /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`).
+ ///
+ /// # Panics
+ ///
+ /// This function will panic when used with a non-async
+ /// [`Store`](`crate::Store`).
+ #[cfg(feature = "async")]
+ pub async fn grow_async(
+ &self,
+ mut store: impl AsContextMut,
+ delta: u32,
+ init: Val,
+ ) -> Result
+ where
+ T: Send,
+ {
+ let mut store = store.as_context_mut();
+ assert!(
+ store.0.async_support(),
+ "cannot use `grow_async` without enabling async support on the config"
+ );
+ store
+ .on_fiber(|store| self.grow(store, delta, init))
+ .await?
+ }
+
+ /// Copy `len` elements from `src_table[src_index..]` into
+ /// `dst_table[dst_index..]`.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if the range is out of bounds of either the source or
+ /// destination tables.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own either `dst_table` or `src_table`.
+ pub fn copy(
+ mut store: impl AsContextMut,
+ dst_table: &Table,
+ dst_index: u32,
+ src_table: &Table,
+ src_index: u32,
+ len: u32,
+ ) -> Result<()> {
+ let store = store.as_context_mut().0;
+ if dst_table.ty(&store).element() != src_table.ty(&store).element() {
+ bail!("tables do not have the same element type");
+ }
+
+ let dst_table = dst_table.wasmtime_table(store, std::iter::empty());
+ let src_range = src_index..(src_index.checked_add(len).unwrap_or(u32::MAX));
+ let src_table = src_table.wasmtime_table(store, src_range);
+ unsafe {
+ runtime::Table::copy(dst_table, src_table, dst_index, src_index, len)?;
+ }
+ Ok(())
+ }
+
+ /// Fill `table[dst..(dst + len)]` with the given value.
+ ///
+ /// # Errors
+ ///
+ /// Returns an error if
+ ///
+ /// * `val` is not of the same type as this table's
+ /// element type,
+ ///
+ /// * the region to be filled is out of bounds, or
+ ///
+ /// * `val` comes from a different `Store` from this table.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `store` does not own either `dst_table` or `src_table`.
+ pub fn fill(&self, mut store: impl AsContextMut, dst: u32, val: Val, len: u32) -> Result<()> {
+ let store = store.as_context_mut().0;
+ let ty = self.ty(&store).element().clone();
+ let val = val.into_table_element(store, ty)?;
+
+ let table = self.wasmtime_table(store, std::iter::empty());
+ unsafe {
+ (*table).fill(dst, val, len)?;
+ }
+
+ Ok(())
+ }
+
+ pub(crate) unsafe fn from_wasmtime_table(
+ wasmtime_export: wasmtime_runtime::ExportTable,
+ store: &mut StoreOpaque,
+ ) -> Table {
+ Table(store.store_data_mut().insert(wasmtime_export))
+ }
+
+ pub(crate) fn wasmtime_ty<'a>(&self, data: &'a StoreData) -> &'a wasmtime_environ::Table {
+ &data[self.0].table.table
+ }
+
+ pub(crate) fn vmimport(&self, store: &StoreOpaque) -> wasmtime_runtime::VMTableImport {
+ let export = &store[self.0];
+ wasmtime_runtime::VMTableImport {
+ from: export.definition,
+ vmctx: export.vmctx,
+ }
+ }
+
+ /// Get a stable hash key for this table.
+ ///
+ /// Even if the same underlying table definition is added to the
+ /// `StoreData` multiple times and becomes multiple `wasmtime::Table`s,
+ /// this hash key will be consistent across all of these tables.
+ #[allow(dead_code)] // Not used yet, but added for consistency.
+ pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl std::hash::Hash + Eq {
+ store[self.0].definition as usize
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{Instance, Module, Store};
+
+ #[test]
+ fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
+ let mut store = Store::<()>::default();
+ let module = Module::new(
+ store.engine(),
+ r#"
+ (module
+ (table (export "t") 1 1 externref)
+ )
+ "#,
+ )?;
+ let instance = Instance::new(&mut store, &module, &[])?;
+
+ // Each time we `get_table`, we call `Table::from_wasmtime` which adds
+ // a new entry to `StoreData`, so `t1` and `t2` will have different
+ // indices into `StoreData`.
+ let t1 = instance.get_table(&mut store, "t").unwrap();
+ let t2 = instance.get_table(&mut store, "t").unwrap();
+
+ // That said, they really point to the same table.
+ assert!(t1.get(&mut store, 0).unwrap().unwrap_externref().is_none());
+ assert!(t2.get(&mut store, 0).unwrap().unwrap_externref().is_none());
+ t1.set(&mut store, 0, Val::ExternRef(Some(ExternRef::new(42))))?;
+ assert!(t1.get(&mut store, 0).unwrap().unwrap_externref().is_some());
+ assert!(t2.get(&mut store, 0).unwrap().unwrap_externref().is_some());
+
+ // And therefore their hash keys are the same.
+ assert!(t1.hash_key(&store.as_context().0) == t2.hash_key(&store.as_context().0));
+
+ // But the hash keys are different from different tables.
+ let instance2 = Instance::new(&mut store, &module, &[])?;
+ let t3 = instance2.get_table(&mut store, "t").unwrap();
+ assert!(t1.hash_key(&store.as_context().0) != t3.hash_key(&store.as_context().0));
+
+ Ok(())
+ }
+}
diff --git a/crates/wasmtime/src/func.rs b/crates/wasmtime/src/func.rs
index 3ec071c72980..8e3a39d004bf 100644
--- a/crates/wasmtime/src/func.rs
+++ b/crates/wasmtime/src/func.rs
@@ -946,9 +946,7 @@ impl Func {
/// this function is properly rooted within it. Additionally this function
/// should not be liberally used since it's a very low-level knob.
pub unsafe fn to_raw(&self, mut store: impl AsContextMut) -> *mut c_void {
- self.caller_checked_func_ref(store.as_context_mut().0)
- .as_ptr()
- .cast()
+ self.vm_func_ref(store.as_context_mut().0).as_ptr().cast()
}
/// Invokes this function with the `params` given, returning the results
@@ -1080,7 +1078,7 @@ impl Func {
}
#[inline]
- pub(crate) fn caller_checked_func_ref(&self, store: &mut StoreOpaque) -> NonNull {
+ pub(crate) fn vm_func_ref(&self, store: &mut StoreOpaque) -> NonNull {
let func_data = &mut store.store_data_mut()[self.0];
if let Some(in_store) = func_data.in_store_func_ref {
in_store.as_non_null()
@@ -1339,6 +1337,16 @@ impl Func {
// (unsafely), which should be safe since we just did the type check above.
unsafe { Ok(TypedFunc::new_unchecked(*self)) }
}
+
+ /// Get a stable hash key for this function.
+ ///
+ /// Even if the same underlying function is added to the `StoreData`
+ /// multiple times and becomes multiple `wasmtime::Func`s, this hash key
+ /// will be consistent across all of these functions.
+ #[allow(dead_code)] // Not used yet, but added for consistency.
+ pub(crate) fn hash_key(&self, store: &mut StoreOpaque) -> impl std::hash::Hash + Eq {
+ self.vm_func_ref(store).as_ptr() as usize
+ }
}
/// Prepares for entrance into WebAssembly.
@@ -2391,3 +2399,47 @@ mod rooted {
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{Instance, Module, Store};
+
+ #[test]
+ fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
+ let mut store = Store::<()>::default();
+ let module = Module::new(
+ store.engine(),
+ r#"
+ (module
+ (func (export "f")
+ nop
+ )
+ )
+ "#,
+ )?;
+ let instance = Instance::new(&mut store, &module, &[])?;
+
+ // Each time we `get_func`, we call `Func::from_wasmtime` which adds a
+ // new entry to `StoreData`, so `f1` and `f2` will have different
+ // indices into `StoreData`.
+ let f1 = instance.get_func(&mut store, "f").unwrap();
+ let f2 = instance.get_func(&mut store, "f").unwrap();
+
+ // But their hash keys are the same.
+ assert!(
+ f1.hash_key(&mut store.as_context_mut().0)
+ == f2.hash_key(&mut store.as_context_mut().0)
+ );
+
+ // But the hash keys are different from different funcs.
+ let instance2 = Instance::new(&mut store, &module, &[])?;
+ let f3 = instance2.get_func(&mut store, "f").unwrap();
+ assert!(
+ f1.hash_key(&mut store.as_context_mut().0)
+ != f3.hash_key(&mut store.as_context_mut().0)
+ );
+
+ Ok(())
+ }
+}
diff --git a/crates/wasmtime/src/func/typed.rs b/crates/wasmtime/src/func/typed.rs
index 8229e14585b3..f1188faad4aa 100644
--- a/crates/wasmtime/src/func/typed.rs
+++ b/crates/wasmtime/src/func/typed.rs
@@ -84,7 +84,7 @@ where
!store.0.async_support(),
"must use `call_async` with async stores"
);
- let func = self.func.caller_checked_func_ref(store.0);
+ let func = self.func.vm_func_ref(store.0);
unsafe { Self::call_raw(&mut store, func, params) }
}
@@ -122,7 +122,7 @@ where
);
store
.on_fiber(|store| {
- let func = self.func.caller_checked_func_ref(store.0);
+ let func = self.func.vm_func_ref(store.0);
unsafe { Self::call_raw(store, func, params) }
})
.await?
@@ -439,7 +439,7 @@ unsafe impl WasmTy for Option {
#[inline]
fn into_abi(self, store: &mut StoreOpaque) -> Self::Abi {
if let Some(f) = self {
- f.caller_checked_func_ref(store).as_ptr()
+ f.vm_func_ref(store).as_ptr()
} else {
ptr::null_mut()
}
diff --git a/crates/wasmtime/src/trampoline/global.rs b/crates/wasmtime/src/trampoline/global.rs
index 263e91b2e34f..50a77811d1e4 100644
--- a/crates/wasmtime/src/trampoline/global.rs
+++ b/crates/wasmtime/src/trampoline/global.rs
@@ -53,9 +53,8 @@ pub fn generate_global_export(
Val::F64(x) => *global.as_f64_bits_mut() = x,
Val::V128(x) => *global.as_u128_mut() = x.into(),
Val::FuncRef(f) => {
- *global.as_func_ref_mut() = f.map_or(ptr::null_mut(), |f| {
- f.caller_checked_func_ref(store).as_ptr()
- })
+ *global.as_func_ref_mut() =
+ f.map_or(ptr::null_mut(), |f| f.vm_func_ref(store).as_ptr())
}
Val::ExternRef(x) => *global.as_externref_mut() = x.map(|x| x.inner),
}
diff --git a/crates/wasmtime/src/values.rs b/crates/wasmtime/src/values.rs
index 87040ec6850f..d5605e962dda 100644
--- a/crates/wasmtime/src/values.rs
+++ b/crates/wasmtime/src/values.rs
@@ -194,9 +194,7 @@ impl Val {
if !f.comes_from_same_store(store) {
bail!("cross-`Store` values are not supported in tables");
}
- Ok(TableElement::FuncRef(
- f.caller_checked_func_ref(store).as_ptr(),
- ))
+ Ok(TableElement::FuncRef(f.vm_func_ref(store).as_ptr()))
}
(Val::FuncRef(None), ValType::FuncRef) => Ok(TableElement::FuncRef(ptr::null_mut())),
(Val::ExternRef(Some(x)), ValType::ExternRef) => {