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.