diff --git a/crates/wasmtime/src/runtime/vm/table.rs b/crates/wasmtime/src/runtime/vm/table.rs index c18b861578e1..dc52dd32fead 100644 --- a/crates/wasmtime/src/runtime/vm/table.rs +++ b/crates/wasmtime/src/runtime/vm/table.rs @@ -7,6 +7,8 @@ use crate::prelude::*; use crate::runtime::vm::vmcontext::{VMFuncRef, VMTableDefinition}; use crate::runtime::vm::{GcStore, SendSyncPtr, VMGcRef, VMStore}; +use core::alloc::Layout; +use core::mem; use core::ops::Range; use core::ptr::{self, NonNull}; use core::slice; @@ -267,6 +269,45 @@ fn wasm_to_table_type(ty: WasmRefType) -> TableElementType { } } +/// Allocate dynamic table elements of the given length. +/// +/// Relies on the fact that our tables' elements are initialized to `None`, +/// which is represented by zero, to allocate pre-zeroed memory from the global +/// allocator and avoid manual zero-initialization. +/// +/// # Safety +/// +/// Should only ever be called with a `T` that is a table element type and where +/// `Option`'s `None` variant is represented with zero. +unsafe fn alloc_dynamic_table_elements(len: usize) -> Result>> { + debug_assert!( + core::mem::MaybeUninit::>::zeroed() + .assume_init() + .is_none(), + "null table elements are represented with zeroed memory" + ); + + if len == 0 { + return Ok(vec![]); + } + + let align = mem::align_of::>(); + + let size = mem::size_of::>(); + let size = size.next_multiple_of(align); + let size = size.checked_mul(len).unwrap(); + + let layout = Layout::from_size_align(size, align)?; + + let ptr = alloc::alloc::alloc_zeroed(layout); + ensure!(!ptr.is_null(), "failed to allocate memory for table"); + + let elems = Vec::>::from_raw_parts(ptr.cast(), len, len); + debug_assert!(elems.iter().all(|e| e.is_none())); + + Ok(elems) +} + impl Table { /// Create a new dynamic (movable) table instance for the specified table plan. pub fn new_dynamic( @@ -277,12 +318,12 @@ impl Table { let (minimum, maximum) = Self::limit_new(ty, store)?; match wasm_to_table_type(ty.ref_type) { TableElementType::Func => Ok(Self::from(DynamicFuncTable { - elements: vec![None; minimum], + elements: unsafe { alloc_dynamic_table_elements(minimum)? }, maximum, lazy_init: tunables.table_lazy_init, })), TableElementType::GcRef => Ok(Self::from(DynamicGcRefTable { - elements: (0..minimum).map(|_| None).collect(), + elements: unsafe { alloc_dynamic_table_elements(minimum)? }, maximum, })), }