diff --git a/crates/wasmtime/src/runtime/externals/table.rs b/crates/wasmtime/src/runtime/externals/table.rs
index 6ddddf51ad51..213d83c735da 100644
--- a/crates/wasmtime/src/runtime/externals/table.rs
+++ b/crates/wasmtime/src/runtime/externals/table.rs
@@ -126,7 +126,18 @@ impl Table {
ty: TableType,
init: Ref,
) -> Result
{
+ init.ensure_matches_ty(store, ty.element())
+ .context("type mismatch: value does not match table element type")?;
let table = generate_table_export(store, limiter, &ty).await?;
+ // Tables are always allocated as all zeroes, so skip the fill below if
+ // the value being inserted is all zeros.
+ if init.is_zero_pattern() {
+ if cfg!(debug_assertions) {
+ let (table, _) = table.wasmtime_table(store, None);
+ table.debug_assert_all_zero();
+ }
+ return Ok(table);
+ }
table._fill(store, 0, init, ty.minimum())?;
Ok(table)
}
@@ -606,6 +617,15 @@ impl Ref {
_ => unreachable!("checked that the value matches the type above"),
}
}
+
+ fn is_zero_pattern(&self) -> bool {
+ match self {
+ Ref::Extern(None) | Ref::Any(None) | Ref::Exn(None) | Ref::Func(None) => true,
+ Ref::Extern(Some(_)) | Ref::Any(Some(_)) | Ref::Exn(Some(_)) | Ref::Func(Some(_)) => {
+ false
+ }
+ }
+ }
}
#[cfg(test)]
diff --git a/crates/wasmtime/src/runtime/trampoline/table.rs b/crates/wasmtime/src/runtime/trampoline/table.rs
index 6700b78ac1ab..4f1ec8decad0 100644
--- a/crates/wasmtime/src/runtime/trampoline/table.rs
+++ b/crates/wasmtime/src/runtime/trampoline/table.rs
@@ -22,6 +22,7 @@ pub async fn create_table(
);
let table_id = module.tables.push(wasmtime_table)?;
+ module.table_initialization.push(Default::default())?;
// TODO: can this `exports.insert` get removed?
let name = module.strings.insert("")?;
diff --git a/crates/wasmtime/src/runtime/vm/table.rs b/crates/wasmtime/src/runtime/vm/table.rs
index 86f43c8deba2..7aba9e9c173f 100644
--- a/crates/wasmtime/src/runtime/vm/table.rs
+++ b/crates/wasmtime/src/runtime/vm/table.rs
@@ -946,6 +946,21 @@ impl Table {
}
}
}
+
+ pub fn debug_assert_all_zero(&self) {
+ match self.element_type() {
+ TableElementType::Func => {
+ let (funcrefs, _lazy_init) = self.funcrefs();
+ debug_assert!(funcrefs.iter().all(|f| f.0.is_none()));
+ }
+ TableElementType::GcRef => {
+ debug_assert!(self.gc_refs().iter().all(|r| r.is_none()));
+ }
+ TableElementType::Cont => {
+ debug_assert!(self.contrefs().iter().all(|c| c.is_none()));
+ }
+ }
+ }
}
// The default table representation is an empty funcref table that cannot grow.