181a89169SAlex Crichton use crate::prelude::*; 272004aadSNick Fitzgerald use crate::runtime::vm::const_expr::{ConstEvalContext, ConstExprEvaluator}; 372004aadSNick Fitzgerald use crate::runtime::vm::imports::Imports; 472004aadSNick Fitzgerald use crate::runtime::vm::instance::{Instance, InstanceHandle}; 572004aadSNick Fitzgerald use crate::runtime::vm::memory::Memory; 672004aadSNick Fitzgerald use crate::runtime::vm::mpk::ProtectionKey; 772004aadSNick Fitzgerald use crate::runtime::vm::table::Table; 8fed24eefSNick Fitzgerald use crate::runtime::vm::{CompiledModuleId, ModuleRuntimeInfo, VMFuncRef, VMGcRef, VMStore}; 9ed20d93dSAlex Crichton use crate::store::{AutoAssertNoGc, InstanceId, StoreOpaque}; 10818966f3SNick Fitzgerald use crate::vm::VMGlobalDefinition; 11c52b941eSAlex Crichton use core::ptr::NonNull; 12e012eedaSAlex Crichton use core::{mem, ptr}; 1372004aadSNick Fitzgerald use wasmtime_environ::{ 1472004aadSNick Fitzgerald DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization, 152a7f0653SAlex Crichton MemoryInitializer, Module, PrimaryMap, SizeOverflow, TableInitialValue, Trap, Tunables, 162a7f0653SAlex Crichton VMOffsets, WasmHeapTopType, 1772004aadSNick Fitzgerald }; 1872004aadSNick Fitzgerald 1972004aadSNick Fitzgerald #[cfg(feature = "gc")] 2072004aadSNick Fitzgerald use crate::runtime::vm::{GcHeap, GcRuntime}; 2172004aadSNick Fitzgerald 2272004aadSNick Fitzgerald #[cfg(feature = "component-model")] 2372004aadSNick Fitzgerald use wasmtime_environ::{ 2472004aadSNick Fitzgerald StaticModuleIndex, 2590ac295eSAlex Crichton component::{Component, VMComponentOffsets}, 2672004aadSNick Fitzgerald }; 2772004aadSNick Fitzgerald 2872004aadSNick Fitzgerald mod on_demand; 2972004aadSNick Fitzgerald pub use self::on_demand::OnDemandInstanceAllocator; 3072004aadSNick Fitzgerald 3172004aadSNick Fitzgerald #[cfg(feature = "pooling-allocator")] 3272004aadSNick Fitzgerald mod pooling; 3372004aadSNick Fitzgerald #[cfg(feature = "pooling-allocator")] 34e1f8b9b7SNick Fitzgerald pub use self::pooling::{ 35e1f8b9b7SNick Fitzgerald InstanceLimits, PoolConcurrencyLimitError, PoolingInstanceAllocator, 36e1f8b9b7SNick Fitzgerald PoolingInstanceAllocatorConfig, 37e1f8b9b7SNick Fitzgerald }; 3872004aadSNick Fitzgerald 3972004aadSNick Fitzgerald /// Represents a request for a new runtime instance. 4072004aadSNick Fitzgerald pub struct InstanceAllocationRequest<'a> { 41ed20d93dSAlex Crichton /// The instance id that this will be assigned within the store once the 42ed20d93dSAlex Crichton /// allocation has finished. 43ed20d93dSAlex Crichton pub id: InstanceId, 44ed20d93dSAlex Crichton 4572004aadSNick Fitzgerald /// The info related to the compiled version of this module, 4672004aadSNick Fitzgerald /// needed for instantiation: function metadata, JIT code 4772004aadSNick Fitzgerald /// addresses, precomputed images for lazy memory and table 4872004aadSNick Fitzgerald /// initialization, and the like. This Arc is cloned and held for 4972004aadSNick Fitzgerald /// the lifetime of the instance. 502835a34bSAlex Crichton pub runtime_info: &'a ModuleRuntimeInfo, 5172004aadSNick Fitzgerald 5272004aadSNick Fitzgerald /// The imports to use for the instantiation. 5372004aadSNick Fitzgerald pub imports: Imports<'a>, 5472004aadSNick Fitzgerald 5572004aadSNick Fitzgerald /// A pointer to the "store" for this instance to be allocated. The store 5672004aadSNick Fitzgerald /// correlates with the `Store` in wasmtime itself, and lots of contextual 5772004aadSNick Fitzgerald /// information about the execution of wasm can be learned through the 5872004aadSNick Fitzgerald /// store. 5972004aadSNick Fitzgerald /// 6072004aadSNick Fitzgerald /// Note that this is a raw pointer and has a static lifetime, both of which 6172004aadSNick Fitzgerald /// are a bit of a lie. This is done purely so a store can learn about 6272004aadSNick Fitzgerald /// itself when it gets called as a host function, and additionally so this 6372004aadSNick Fitzgerald /// runtime can access internals as necessary (such as the 6472004aadSNick Fitzgerald /// VMExternRefActivationsTable or the resource limiter methods). 6572004aadSNick Fitzgerald /// 6672004aadSNick Fitzgerald /// Note that this ends up being a self-pointer to the instance when stored. 6772004aadSNick Fitzgerald /// The reason is that the instance itself is then stored within the store. 6872004aadSNick Fitzgerald /// We use a number of `PhantomPinned` declarations to indicate this to the 6972004aadSNick Fitzgerald /// compiler. More info on this in `wasmtime/src/store.rs` 7072004aadSNick Fitzgerald pub store: StorePtr, 7172004aadSNick Fitzgerald 7272004aadSNick Fitzgerald /// Indicates '--wmemcheck' flag. 73838ed2d0SAlex Crichton #[cfg(feature = "wmemcheck")] 7472004aadSNick Fitzgerald pub wmemcheck: bool, 7572004aadSNick Fitzgerald 7672004aadSNick Fitzgerald /// Request that the instance's memories be protected by a specific 7772004aadSNick Fitzgerald /// protection key. 7824620d9fSAlex Crichton #[cfg_attr( 7924620d9fSAlex Crichton not(feature = "pooling-allocator"), 8024620d9fSAlex Crichton expect( 8124620d9fSAlex Crichton dead_code, 8224620d9fSAlex Crichton reason = "easier to keep this field than remove it, not perf-critical to remove" 8324620d9fSAlex Crichton ) 8424620d9fSAlex Crichton )] 8572004aadSNick Fitzgerald pub pkey: Option<ProtectionKey>, 867a49e44fSAlex Crichton 877a49e44fSAlex Crichton /// Tunable configuration options the engine is using. 887a49e44fSAlex Crichton pub tunables: &'a Tunables, 8972004aadSNick Fitzgerald } 9072004aadSNick Fitzgerald 9172004aadSNick Fitzgerald /// A pointer to a Store. This Option<*mut dyn Store> is wrapped in a struct 9272004aadSNick Fitzgerald /// so that the function to create a &mut dyn Store is a method on a member of 9372004aadSNick Fitzgerald /// InstanceAllocationRequest, rather than on a &mut InstanceAllocationRequest 9472004aadSNick Fitzgerald /// itself, because several use-sites require a split mut borrow on the 9572004aadSNick Fitzgerald /// InstanceAllocationRequest. 96c3559d4aSAlex Crichton pub struct StorePtr(Option<NonNull<dyn VMStore>>); 9772004aadSNick Fitzgerald 984d77cf25SNick Fitzgerald // We can't make `VMStore: Send + Sync` because that requires making all of 994d77cf25SNick Fitzgerald // Wastime's internals generic over the `Store`'s `T`. So instead, we take care 1004d77cf25SNick Fitzgerald // in the whole VM layer to only use the `VMStore` in ways that are `Send`- and 1014d77cf25SNick Fitzgerald // `Sync`-safe and we have to have these unsafe impls. 1024d77cf25SNick Fitzgerald unsafe impl Send for StorePtr {} 1034d77cf25SNick Fitzgerald unsafe impl Sync for StorePtr {} 1044d77cf25SNick Fitzgerald 10572004aadSNick Fitzgerald impl StorePtr { 10672004aadSNick Fitzgerald /// A pointer to no Store. 10772004aadSNick Fitzgerald pub fn empty() -> Self { 10872004aadSNick Fitzgerald Self(None) 10972004aadSNick Fitzgerald } 11072004aadSNick Fitzgerald 11172004aadSNick Fitzgerald /// A pointer to a Store. 112c3559d4aSAlex Crichton pub fn new(ptr: NonNull<dyn VMStore>) -> Self { 11372004aadSNick Fitzgerald Self(Some(ptr)) 11472004aadSNick Fitzgerald } 11572004aadSNick Fitzgerald 11672004aadSNick Fitzgerald /// The raw contents of this struct 117c3559d4aSAlex Crichton pub fn as_raw(&self) -> Option<NonNull<dyn VMStore>> { 1180c0153c1SNick Fitzgerald self.0 11972004aadSNick Fitzgerald } 12072004aadSNick Fitzgerald 12172004aadSNick Fitzgerald /// Use the StorePtr as a mut ref to the Store. 12272004aadSNick Fitzgerald /// 12372004aadSNick Fitzgerald /// Safety: must not be used outside the original lifetime of the borrow. 124fed24eefSNick Fitzgerald pub(crate) unsafe fn get(&mut self) -> Option<&mut dyn VMStore> { 125*b052dee0SAlex Crichton let ptr = unsafe { self.0?.as_mut() }; 126c3559d4aSAlex Crichton Some(ptr) 12772004aadSNick Fitzgerald } 12872004aadSNick Fitzgerald } 12972004aadSNick Fitzgerald 13072004aadSNick Fitzgerald /// The index of a memory allocation within an `InstanceAllocator`. 13172004aadSNick Fitzgerald #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] 13272004aadSNick Fitzgerald pub struct MemoryAllocationIndex(u32); 13372004aadSNick Fitzgerald 13472004aadSNick Fitzgerald impl Default for MemoryAllocationIndex { 13572004aadSNick Fitzgerald fn default() -> Self { 13672004aadSNick Fitzgerald // A default `MemoryAllocationIndex` that can be used with 13772004aadSNick Fitzgerald // `InstanceAllocator`s that don't actually need indices. 13872004aadSNick Fitzgerald MemoryAllocationIndex(u32::MAX) 13972004aadSNick Fitzgerald } 14072004aadSNick Fitzgerald } 14172004aadSNick Fitzgerald 14272004aadSNick Fitzgerald impl MemoryAllocationIndex { 14372004aadSNick Fitzgerald /// Get the underlying index of this `MemoryAllocationIndex`. 14424620d9fSAlex Crichton #[cfg(feature = "pooling-allocator")] 14572004aadSNick Fitzgerald pub fn index(&self) -> usize { 14672004aadSNick Fitzgerald self.0 as usize 14772004aadSNick Fitzgerald } 14872004aadSNick Fitzgerald } 14972004aadSNick Fitzgerald 15072004aadSNick Fitzgerald /// The index of a table allocation within an `InstanceAllocator`. 15172004aadSNick Fitzgerald #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] 15272004aadSNick Fitzgerald pub struct TableAllocationIndex(u32); 15372004aadSNick Fitzgerald 15472004aadSNick Fitzgerald impl Default for TableAllocationIndex { 15572004aadSNick Fitzgerald fn default() -> Self { 15672004aadSNick Fitzgerald // A default `TableAllocationIndex` that can be used with 15772004aadSNick Fitzgerald // `InstanceAllocator`s that don't actually need indices. 15872004aadSNick Fitzgerald TableAllocationIndex(u32::MAX) 15972004aadSNick Fitzgerald } 16072004aadSNick Fitzgerald } 16172004aadSNick Fitzgerald 16272004aadSNick Fitzgerald impl TableAllocationIndex { 16372004aadSNick Fitzgerald /// Get the underlying index of this `TableAllocationIndex`. 16424620d9fSAlex Crichton #[cfg(feature = "pooling-allocator")] 16572004aadSNick Fitzgerald pub fn index(&self) -> usize { 16672004aadSNick Fitzgerald self.0 as usize 16772004aadSNick Fitzgerald } 16872004aadSNick Fitzgerald } 16972004aadSNick Fitzgerald 17072004aadSNick Fitzgerald /// The index of a table allocation within an `InstanceAllocator`. 17172004aadSNick Fitzgerald #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] 17272004aadSNick Fitzgerald pub struct GcHeapAllocationIndex(u32); 17372004aadSNick Fitzgerald 17472004aadSNick Fitzgerald impl Default for GcHeapAllocationIndex { 17572004aadSNick Fitzgerald fn default() -> Self { 17672004aadSNick Fitzgerald // A default `GcHeapAllocationIndex` that can be used with 17772004aadSNick Fitzgerald // `InstanceAllocator`s that don't actually need indices. 17872004aadSNick Fitzgerald GcHeapAllocationIndex(u32::MAX) 17972004aadSNick Fitzgerald } 18072004aadSNick Fitzgerald } 18172004aadSNick Fitzgerald 18272004aadSNick Fitzgerald impl GcHeapAllocationIndex { 18372004aadSNick Fitzgerald /// Get the underlying index of this `GcHeapAllocationIndex`. 18472004aadSNick Fitzgerald pub fn index(&self) -> usize { 18572004aadSNick Fitzgerald self.0 as usize 18672004aadSNick Fitzgerald } 18772004aadSNick Fitzgerald } 18872004aadSNick Fitzgerald 18972004aadSNick Fitzgerald /// Trait that represents the hooks needed to implement an instance allocator. 19072004aadSNick Fitzgerald /// 19172004aadSNick Fitzgerald /// Implement this trait when implementing new instance allocators, but don't 19272004aadSNick Fitzgerald /// use this trait when you need an instance allocator. Instead use the 19372004aadSNick Fitzgerald /// `InstanceAllocator` trait for that, which has additional helper methods and 19472004aadSNick Fitzgerald /// a blanket implementation for all types that implement this trait. 19572004aadSNick Fitzgerald /// 19672004aadSNick Fitzgerald /// # Safety 19772004aadSNick Fitzgerald /// 19872004aadSNick Fitzgerald /// This trait is unsafe as it requires knowledge of Wasmtime's runtime 19972004aadSNick Fitzgerald /// internals to implement correctly. 20072004aadSNick Fitzgerald pub unsafe trait InstanceAllocatorImpl { 20172004aadSNick Fitzgerald /// Validate whether a component (including all of its contained core 20272004aadSNick Fitzgerald /// modules) is allocatable by this instance allocator. 20372004aadSNick Fitzgerald #[cfg(feature = "component-model")] 20472004aadSNick Fitzgerald fn validate_component_impl<'a>( 20572004aadSNick Fitzgerald &self, 20672004aadSNick Fitzgerald component: &Component, 20772004aadSNick Fitzgerald offsets: &VMComponentOffsets<HostPtr>, 20872004aadSNick Fitzgerald get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module, 20972004aadSNick Fitzgerald ) -> Result<()>; 21072004aadSNick Fitzgerald 21172004aadSNick Fitzgerald /// Validate whether a module is allocatable by this instance allocator. 21272004aadSNick Fitzgerald fn validate_module_impl(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()>; 21372004aadSNick Fitzgerald 214c22b3cb9SNick Fitzgerald /// Validate whether a memory is allocatable by this instance allocator. 215c22b3cb9SNick Fitzgerald #[cfg(feature = "gc")] 216c22b3cb9SNick Fitzgerald fn validate_memory_impl(&self, memory: &wasmtime_environ::Memory) -> Result<()>; 217c22b3cb9SNick Fitzgerald 21872004aadSNick Fitzgerald /// Increment the count of concurrent component instances that are currently 21972004aadSNick Fitzgerald /// allocated, if applicable. 22072004aadSNick Fitzgerald /// 22172004aadSNick Fitzgerald /// Not all instance allocators will have limits for the maximum number of 22272004aadSNick Fitzgerald /// concurrent component instances that can be live at the same time, and 22372004aadSNick Fitzgerald /// these allocators may implement this method with a no-op. 22472004aadSNick Fitzgerald // 22572004aadSNick Fitzgerald // Note: It would be nice to have an associated type that on construction 22672004aadSNick Fitzgerald // does the increment and on drop does the decrement but there are two 22772004aadSNick Fitzgerald // problems with this: 22872004aadSNick Fitzgerald // 22972004aadSNick Fitzgerald // 1. This trait's implementations are always used as trait objects, and 23072004aadSNick Fitzgerald // associated types are not object safe. 23172004aadSNick Fitzgerald // 23272004aadSNick Fitzgerald // 2. We would want a parameterized `Drop` implementation so that we could 23372004aadSNick Fitzgerald // pass in the `InstanceAllocatorImpl` on drop, but this doesn't exist in 23472004aadSNick Fitzgerald // Rust. Therefore, we would be forced to add reference counting and 23572004aadSNick Fitzgerald // stuff like that to keep a handle on the instance allocator from this 23672004aadSNick Fitzgerald // theoretical type. That's a bummer. 237ef921e81SAlex Crichton #[cfg(feature = "component-model")] 23872004aadSNick Fitzgerald fn increment_component_instance_count(&self) -> Result<()>; 23972004aadSNick Fitzgerald 24072004aadSNick Fitzgerald /// The dual of `increment_component_instance_count`. 241ef921e81SAlex Crichton #[cfg(feature = "component-model")] 24272004aadSNick Fitzgerald fn decrement_component_instance_count(&self); 24372004aadSNick Fitzgerald 24472004aadSNick Fitzgerald /// Increment the count of concurrent core module instances that are 24572004aadSNick Fitzgerald /// currently allocated, if applicable. 24672004aadSNick Fitzgerald /// 24772004aadSNick Fitzgerald /// Not all instance allocators will have limits for the maximum number of 24872004aadSNick Fitzgerald /// concurrent core module instances that can be live at the same time, and 24972004aadSNick Fitzgerald /// these allocators may implement this method with a no-op. 25072004aadSNick Fitzgerald fn increment_core_instance_count(&self) -> Result<()>; 25172004aadSNick Fitzgerald 25272004aadSNick Fitzgerald /// The dual of `increment_core_instance_count`. 25372004aadSNick Fitzgerald fn decrement_core_instance_count(&self); 25472004aadSNick Fitzgerald 25572004aadSNick Fitzgerald /// Allocate a memory for an instance. 25672004aadSNick Fitzgerald /// 25772004aadSNick Fitzgerald /// # Unsafety 25872004aadSNick Fitzgerald /// 25972004aadSNick Fitzgerald /// The memory and its associated module must have already been validated by 260c22b3cb9SNick Fitzgerald /// `Self::validate_memory` (or transtively via 261c22b3cb9SNick Fitzgerald /// `Self::validate_{module,component}`) and passed that validation. 26272004aadSNick Fitzgerald unsafe fn allocate_memory( 26372004aadSNick Fitzgerald &self, 26472004aadSNick Fitzgerald request: &mut InstanceAllocationRequest, 2652a7f0653SAlex Crichton ty: &wasmtime_environ::Memory, 2662a7f0653SAlex Crichton tunables: &Tunables, 267c22b3cb9SNick Fitzgerald memory_index: Option<DefinedMemoryIndex>, 26872004aadSNick Fitzgerald ) -> Result<(MemoryAllocationIndex, Memory)>; 26972004aadSNick Fitzgerald 27072004aadSNick Fitzgerald /// Deallocate an instance's previously allocated memory. 27172004aadSNick Fitzgerald /// 27272004aadSNick Fitzgerald /// # Unsafety 27372004aadSNick Fitzgerald /// 27472004aadSNick Fitzgerald /// The memory must have previously been allocated by 27572004aadSNick Fitzgerald /// `Self::allocate_memory`, be at the given index, and must currently be 27672004aadSNick Fitzgerald /// allocated. It must never be used again. 27772004aadSNick Fitzgerald unsafe fn deallocate_memory( 27872004aadSNick Fitzgerald &self, 279c22b3cb9SNick Fitzgerald memory_index: Option<DefinedMemoryIndex>, 28072004aadSNick Fitzgerald allocation_index: MemoryAllocationIndex, 28172004aadSNick Fitzgerald memory: Memory, 28272004aadSNick Fitzgerald ); 28372004aadSNick Fitzgerald 28472004aadSNick Fitzgerald /// Allocate a table for an instance. 28572004aadSNick Fitzgerald /// 28672004aadSNick Fitzgerald /// # Unsafety 28772004aadSNick Fitzgerald /// 28872004aadSNick Fitzgerald /// The table and its associated module must have already been validated by 28972004aadSNick Fitzgerald /// `Self::validate_module` and passed that validation. 29072004aadSNick Fitzgerald unsafe fn allocate_table( 29172004aadSNick Fitzgerald &self, 29272004aadSNick Fitzgerald req: &mut InstanceAllocationRequest, 2937a49e44fSAlex Crichton table: &wasmtime_environ::Table, 2947a49e44fSAlex Crichton tunables: &Tunables, 29572004aadSNick Fitzgerald table_index: DefinedTableIndex, 29672004aadSNick Fitzgerald ) -> Result<(TableAllocationIndex, Table)>; 29772004aadSNick Fitzgerald 29872004aadSNick Fitzgerald /// Deallocate an instance's previously allocated table. 29972004aadSNick Fitzgerald /// 30072004aadSNick Fitzgerald /// # Unsafety 30172004aadSNick Fitzgerald /// 30272004aadSNick Fitzgerald /// The table must have previously been allocated by `Self::allocate_table`, 30372004aadSNick Fitzgerald /// be at the given index, and must currently be allocated. It must never be 30472004aadSNick Fitzgerald /// used again. 30572004aadSNick Fitzgerald unsafe fn deallocate_table( 30672004aadSNick Fitzgerald &self, 30772004aadSNick Fitzgerald table_index: DefinedTableIndex, 30872004aadSNick Fitzgerald allocation_index: TableAllocationIndex, 30972004aadSNick Fitzgerald table: Table, 31072004aadSNick Fitzgerald ); 31172004aadSNick Fitzgerald 31272004aadSNick Fitzgerald /// Allocates a fiber stack for calling async functions on. 31372004aadSNick Fitzgerald #[cfg(feature = "async")] 31472004aadSNick Fitzgerald fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack>; 31572004aadSNick Fitzgerald 31672004aadSNick Fitzgerald /// Deallocates a fiber stack that was previously allocated with 31772004aadSNick Fitzgerald /// `allocate_fiber_stack`. 31872004aadSNick Fitzgerald /// 31972004aadSNick Fitzgerald /// # Safety 32072004aadSNick Fitzgerald /// 32172004aadSNick Fitzgerald /// The provided stack is required to have been allocated with 32272004aadSNick Fitzgerald /// `allocate_fiber_stack`. 32372004aadSNick Fitzgerald #[cfg(feature = "async")] 324e1f8b9b7SNick Fitzgerald unsafe fn deallocate_fiber_stack(&self, stack: wasmtime_fiber::FiberStack); 32572004aadSNick Fitzgerald 32672004aadSNick Fitzgerald /// Allocate a GC heap for allocating Wasm GC objects within. 32772004aadSNick Fitzgerald #[cfg(feature = "gc")] 32872004aadSNick Fitzgerald fn allocate_gc_heap( 32972004aadSNick Fitzgerald &self, 330eafe7439SNick Fitzgerald engine: &crate::Engine, 33172004aadSNick Fitzgerald gc_runtime: &dyn GcRuntime, 332c22b3cb9SNick Fitzgerald memory_alloc_index: MemoryAllocationIndex, 333c22b3cb9SNick Fitzgerald memory: Memory, 33472004aadSNick Fitzgerald ) -> Result<(GcHeapAllocationIndex, Box<dyn GcHeap>)>; 33572004aadSNick Fitzgerald 33672004aadSNick Fitzgerald /// Deallocate a GC heap that was previously allocated with 33772004aadSNick Fitzgerald /// `allocate_gc_heap`. 33872004aadSNick Fitzgerald #[cfg(feature = "gc")] 339c22b3cb9SNick Fitzgerald #[must_use = "it is the caller's responsibility to deallocate the GC heap's underlying memory \ 340c22b3cb9SNick Fitzgerald storage after the GC heap is deallocated"] 341c22b3cb9SNick Fitzgerald fn deallocate_gc_heap( 342c22b3cb9SNick Fitzgerald &self, 343c22b3cb9SNick Fitzgerald allocation_index: GcHeapAllocationIndex, 344c22b3cb9SNick Fitzgerald gc_heap: Box<dyn GcHeap>, 345c22b3cb9SNick Fitzgerald ) -> (MemoryAllocationIndex, Memory); 34672004aadSNick Fitzgerald 34772004aadSNick Fitzgerald /// Purges all lingering resources related to `module` from within this 34872004aadSNick Fitzgerald /// allocator. 34972004aadSNick Fitzgerald /// 35072004aadSNick Fitzgerald /// Primarily present for the pooling allocator to remove mappings of 35172004aadSNick Fitzgerald /// this module from slots in linear memory. 35272004aadSNick Fitzgerald fn purge_module(&self, module: CompiledModuleId); 35372004aadSNick Fitzgerald 35472004aadSNick Fitzgerald /// Use the next available protection key. 35572004aadSNick Fitzgerald /// 35672004aadSNick Fitzgerald /// The pooling allocator can use memory protection keys (MPK) for 35772004aadSNick Fitzgerald /// compressing the guard regions protecting against OOB. Each 35872004aadSNick Fitzgerald /// pool-allocated store needs its own key. 35972004aadSNick Fitzgerald fn next_available_pkey(&self) -> Option<ProtectionKey>; 36072004aadSNick Fitzgerald 36172004aadSNick Fitzgerald /// Restrict access to memory regions protected by `pkey`. 36272004aadSNick Fitzgerald /// 36372004aadSNick Fitzgerald /// This is useful for the pooling allocator, which can use memory 36472004aadSNick Fitzgerald /// protection keys (MPK). Note: this may still allow access to other 36572004aadSNick Fitzgerald /// protection keys, such as the default kernel key; see implementations of 36672004aadSNick Fitzgerald /// this. 36772004aadSNick Fitzgerald fn restrict_to_pkey(&self, pkey: ProtectionKey); 36872004aadSNick Fitzgerald 36972004aadSNick Fitzgerald /// Allow access to memory regions protected by any protection key. 37072004aadSNick Fitzgerald fn allow_all_pkeys(&self); 37172004aadSNick Fitzgerald } 37272004aadSNick Fitzgerald 37372004aadSNick Fitzgerald /// A thing that can allocate instances. 37472004aadSNick Fitzgerald /// 37572004aadSNick Fitzgerald /// Don't implement this trait directly, instead implement 37672004aadSNick Fitzgerald /// `InstanceAllocatorImpl` and you'll get this trait for free via a blanket 37772004aadSNick Fitzgerald /// impl. 37872004aadSNick Fitzgerald pub trait InstanceAllocator: InstanceAllocatorImpl { 37972004aadSNick Fitzgerald /// Validate whether a component (including all of its contained core 38072004aadSNick Fitzgerald /// modules) is allocatable with this instance allocator. 38172004aadSNick Fitzgerald #[cfg(feature = "component-model")] 38272004aadSNick Fitzgerald fn validate_component<'a>( 38372004aadSNick Fitzgerald &self, 38472004aadSNick Fitzgerald component: &Component, 38572004aadSNick Fitzgerald offsets: &VMComponentOffsets<HostPtr>, 38672004aadSNick Fitzgerald get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module, 38772004aadSNick Fitzgerald ) -> Result<()> { 38872004aadSNick Fitzgerald InstanceAllocatorImpl::validate_component_impl(self, component, offsets, get_module) 38972004aadSNick Fitzgerald } 39072004aadSNick Fitzgerald 39172004aadSNick Fitzgerald /// Validate whether a core module is allocatable with this instance 39272004aadSNick Fitzgerald /// allocator. 39372004aadSNick Fitzgerald fn validate_module(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()> { 39472004aadSNick Fitzgerald InstanceAllocatorImpl::validate_module_impl(self, module, offsets) 39572004aadSNick Fitzgerald } 39672004aadSNick Fitzgerald 397c22b3cb9SNick Fitzgerald /// Validate whether a memory is allocatable with this instance allocator. 398c22b3cb9SNick Fitzgerald #[cfg(feature = "gc")] 399c22b3cb9SNick Fitzgerald fn validate_memory(&self, memory: &wasmtime_environ::Memory) -> Result<()> { 400c22b3cb9SNick Fitzgerald InstanceAllocatorImpl::validate_memory_impl(self, memory) 401c22b3cb9SNick Fitzgerald } 402c22b3cb9SNick Fitzgerald 40372004aadSNick Fitzgerald /// Allocates a fresh `InstanceHandle` for the `req` given. 40472004aadSNick Fitzgerald /// 40572004aadSNick Fitzgerald /// This will allocate memories and tables internally from this allocator 40672004aadSNick Fitzgerald /// and weave that altogether into a final and complete `InstanceHandle` 40772004aadSNick Fitzgerald /// ready to be registered with a store. 40872004aadSNick Fitzgerald /// 40972004aadSNick Fitzgerald /// Note that the returned instance must still have `.initialize(..)` called 41072004aadSNick Fitzgerald /// on it to complete the instantiation process. 41172004aadSNick Fitzgerald /// 41272004aadSNick Fitzgerald /// # Unsafety 41372004aadSNick Fitzgerald /// 41472004aadSNick Fitzgerald /// The request's associated module, memories, tables, and vmctx must have 41572004aadSNick Fitzgerald /// already have been validated by `Self::validate_module`. 41672004aadSNick Fitzgerald unsafe fn allocate_module( 41772004aadSNick Fitzgerald &self, 41872004aadSNick Fitzgerald mut request: InstanceAllocationRequest, 41972004aadSNick Fitzgerald ) -> Result<InstanceHandle> { 4202bdae8b6SNick Fitzgerald let module = request.runtime_info.env_module(); 42172004aadSNick Fitzgerald 42272004aadSNick Fitzgerald #[cfg(debug_assertions)] 42372004aadSNick Fitzgerald InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets()) 42472004aadSNick Fitzgerald .expect("module should have already been validated before allocation"); 42572004aadSNick Fitzgerald 42672004aadSNick Fitzgerald self.increment_core_instance_count()?; 42772004aadSNick Fitzgerald 4282a7f0653SAlex Crichton let num_defined_memories = module.num_defined_memories(); 42972004aadSNick Fitzgerald let mut memories = PrimaryMap::with_capacity(num_defined_memories); 43072004aadSNick Fitzgerald 4317a49e44fSAlex Crichton let num_defined_tables = module.num_defined_tables(); 43272004aadSNick Fitzgerald let mut tables = PrimaryMap::with_capacity(num_defined_tables); 43372004aadSNick Fitzgerald 43472004aadSNick Fitzgerald match (|| { 435*b052dee0SAlex Crichton // SAFETY: validation of tables/memories is a contract of this 436*b052dee0SAlex Crichton // function. 437*b052dee0SAlex Crichton unsafe { 43872004aadSNick Fitzgerald self.allocate_memories(&mut request, &mut memories)?; 43972004aadSNick Fitzgerald self.allocate_tables(&mut request, &mut tables)?; 440*b052dee0SAlex Crichton } 44172004aadSNick Fitzgerald Ok(()) 44272004aadSNick Fitzgerald })() { 4432a7f0653SAlex Crichton Ok(_) => Ok(Instance::new(request, memories, tables, &module.memories)), 44472004aadSNick Fitzgerald Err(e) => { 445*b052dee0SAlex Crichton // SAFETY: these were previously allocated by this allocator 446*b052dee0SAlex Crichton unsafe { 44772004aadSNick Fitzgerald self.deallocate_memories(&mut memories); 44872004aadSNick Fitzgerald self.deallocate_tables(&mut tables); 449*b052dee0SAlex Crichton } 45072004aadSNick Fitzgerald self.decrement_core_instance_count(); 45172004aadSNick Fitzgerald Err(e) 45272004aadSNick Fitzgerald } 45372004aadSNick Fitzgerald } 45472004aadSNick Fitzgerald } 45572004aadSNick Fitzgerald 45672004aadSNick Fitzgerald /// Deallocates the provided instance. 45772004aadSNick Fitzgerald /// 45872004aadSNick Fitzgerald /// This will null-out the pointer within `handle` and otherwise reclaim 45972004aadSNick Fitzgerald /// resources such as tables, memories, and the instance memory itself. 46072004aadSNick Fitzgerald /// 46172004aadSNick Fitzgerald /// # Unsafety 46272004aadSNick Fitzgerald /// 46372004aadSNick Fitzgerald /// The instance must have previously been allocated by `Self::allocate`. 46472004aadSNick Fitzgerald unsafe fn deallocate_module(&self, handle: &mut InstanceHandle) { 465*b052dee0SAlex Crichton // SAFETY: the contract of `deallocate_*` is itself a contract of this 466*b052dee0SAlex Crichton // function, that the memories/tables were previously allocated from 467*b052dee0SAlex Crichton // here. 468*b052dee0SAlex Crichton unsafe { 469aad93a48SAlex Crichton self.deallocate_memories(handle.get_mut().memories_mut()); 470aad93a48SAlex Crichton self.deallocate_tables(handle.get_mut().tables_mut()); 471*b052dee0SAlex Crichton } 47272004aadSNick Fitzgerald 47372004aadSNick Fitzgerald self.decrement_core_instance_count(); 47472004aadSNick Fitzgerald } 47572004aadSNick Fitzgerald 47672004aadSNick Fitzgerald /// Allocate the memories for the given instance allocation request, pushing 47772004aadSNick Fitzgerald /// them into `memories`. 47872004aadSNick Fitzgerald /// 47972004aadSNick Fitzgerald /// # Unsafety 48072004aadSNick Fitzgerald /// 48172004aadSNick Fitzgerald /// The request's associated module and memories must have previously been 48272004aadSNick Fitzgerald /// validated by `Self::validate_module`. 48372004aadSNick Fitzgerald unsafe fn allocate_memories( 48472004aadSNick Fitzgerald &self, 48572004aadSNick Fitzgerald request: &mut InstanceAllocationRequest, 48672004aadSNick Fitzgerald memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, 48772004aadSNick Fitzgerald ) -> Result<()> { 4882bdae8b6SNick Fitzgerald let module = request.runtime_info.env_module(); 48972004aadSNick Fitzgerald 49072004aadSNick Fitzgerald #[cfg(debug_assertions)] 49172004aadSNick Fitzgerald InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets()) 49272004aadSNick Fitzgerald .expect("module should have already been validated before allocation"); 49372004aadSNick Fitzgerald 4942a7f0653SAlex Crichton for (memory_index, ty) in module.memories.iter().skip(module.num_imported_memories) { 49572004aadSNick Fitzgerald let memory_index = module 49672004aadSNick Fitzgerald .defined_memory_index(memory_index) 49772004aadSNick Fitzgerald .expect("should be a defined memory since we skipped imported ones"); 49872004aadSNick Fitzgerald 499*b052dee0SAlex Crichton // SAFETY: validation of the memory from this allocator is itself a 500*b052dee0SAlex Crichton // contract of this function. 501*b052dee0SAlex Crichton let memory = 502*b052dee0SAlex Crichton unsafe { self.allocate_memory(request, ty, request.tunables, Some(memory_index))? }; 503*b052dee0SAlex Crichton memories.push(memory); 50472004aadSNick Fitzgerald } 50572004aadSNick Fitzgerald 50672004aadSNick Fitzgerald Ok(()) 50772004aadSNick Fitzgerald } 50872004aadSNick Fitzgerald 50972004aadSNick Fitzgerald /// Deallocate all the memories in the given primary map. 51072004aadSNick Fitzgerald /// 51172004aadSNick Fitzgerald /// # Unsafety 51272004aadSNick Fitzgerald /// 51372004aadSNick Fitzgerald /// The memories must have previously been allocated by 51472004aadSNick Fitzgerald /// `Self::allocate_memories`. 51572004aadSNick Fitzgerald unsafe fn deallocate_memories( 51672004aadSNick Fitzgerald &self, 51772004aadSNick Fitzgerald memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, 51872004aadSNick Fitzgerald ) { 51972004aadSNick Fitzgerald for (memory_index, (allocation_index, memory)) in mem::take(memories) { 52072004aadSNick Fitzgerald // Because deallocating memory is infallible, we don't need to worry 52172004aadSNick Fitzgerald // about leaking subsequent memories if the first memory failed to 52272004aadSNick Fitzgerald // deallocate. If deallocating memory ever becomes fallible, we will 52372004aadSNick Fitzgerald // need to be careful here! 524*b052dee0SAlex Crichton // 525*b052dee0SAlex Crichton // SAFETY: the unsafe contract here is the same as the unsafe 526*b052dee0SAlex Crichton // contract of this function, that the memories were previously 527*b052dee0SAlex Crichton // allocated by this allocator. 528*b052dee0SAlex Crichton unsafe { 529c22b3cb9SNick Fitzgerald self.deallocate_memory(Some(memory_index), allocation_index, memory); 53072004aadSNick Fitzgerald } 53172004aadSNick Fitzgerald } 532*b052dee0SAlex Crichton } 53372004aadSNick Fitzgerald 53472004aadSNick Fitzgerald /// Allocate tables for the given instance allocation request, pushing them 53572004aadSNick Fitzgerald /// into `tables`. 53672004aadSNick Fitzgerald /// 53772004aadSNick Fitzgerald /// # Unsafety 53872004aadSNick Fitzgerald /// 53972004aadSNick Fitzgerald /// The request's associated module and tables must have previously been 54072004aadSNick Fitzgerald /// validated by `Self::validate_module`. 54172004aadSNick Fitzgerald unsafe fn allocate_tables( 54272004aadSNick Fitzgerald &self, 54372004aadSNick Fitzgerald request: &mut InstanceAllocationRequest, 54472004aadSNick Fitzgerald tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 54572004aadSNick Fitzgerald ) -> Result<()> { 5462bdae8b6SNick Fitzgerald let module = request.runtime_info.env_module(); 54772004aadSNick Fitzgerald 54872004aadSNick Fitzgerald #[cfg(debug_assertions)] 54972004aadSNick Fitzgerald InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets()) 55072004aadSNick Fitzgerald .expect("module should have already been validated before allocation"); 55172004aadSNick Fitzgerald 5527a49e44fSAlex Crichton for (index, table) in module.tables.iter().skip(module.num_imported_tables) { 55372004aadSNick Fitzgerald let def_index = module 55472004aadSNick Fitzgerald .defined_table_index(index) 55572004aadSNick Fitzgerald .expect("should be a defined table since we skipped imported ones"); 55672004aadSNick Fitzgerald 557*b052dee0SAlex Crichton // SAFETY: the contract here is that the table has been validated by 558*b052dee0SAlex Crichton // this allocator which is a contract of this function itself. 559*b052dee0SAlex Crichton let table = 560*b052dee0SAlex Crichton unsafe { self.allocate_table(request, table, request.tunables, def_index)? }; 561*b052dee0SAlex Crichton tables.push(table); 56272004aadSNick Fitzgerald } 56372004aadSNick Fitzgerald 56472004aadSNick Fitzgerald Ok(()) 56572004aadSNick Fitzgerald } 56672004aadSNick Fitzgerald 56772004aadSNick Fitzgerald /// Deallocate all the tables in the given primary map. 56872004aadSNick Fitzgerald /// 56972004aadSNick Fitzgerald /// # Unsafety 57072004aadSNick Fitzgerald /// 57172004aadSNick Fitzgerald /// The tables must have previously been allocated by 57272004aadSNick Fitzgerald /// `Self::allocate_tables`. 57372004aadSNick Fitzgerald unsafe fn deallocate_tables( 57472004aadSNick Fitzgerald &self, 57572004aadSNick Fitzgerald tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 57672004aadSNick Fitzgerald ) { 57772004aadSNick Fitzgerald for (table_index, (allocation_index, table)) in mem::take(tables) { 578*b052dee0SAlex Crichton // SAFETY: the tables here were allocated from this allocator per 579*b052dee0SAlex Crichton // the contract on this function itself. 580*b052dee0SAlex Crichton unsafe { 58172004aadSNick Fitzgerald self.deallocate_table(table_index, allocation_index, table); 58272004aadSNick Fitzgerald } 58372004aadSNick Fitzgerald } 58472004aadSNick Fitzgerald } 585*b052dee0SAlex Crichton } 58672004aadSNick Fitzgerald 58772004aadSNick Fitzgerald // Every `InstanceAllocatorImpl` is an `InstanceAllocator` when used 58872004aadSNick Fitzgerald // correctly. Also, no one is allowed to override this trait's methods, they 58972004aadSNick Fitzgerald // must use the defaults. This blanket impl provides both of those things. 59072004aadSNick Fitzgerald impl<T: InstanceAllocatorImpl> InstanceAllocator for T {} 59172004aadSNick Fitzgerald 5928818b251SNick Fitzgerald fn check_table_init_bounds( 5938818b251SNick Fitzgerald store: &mut StoreOpaque, 594aad93a48SAlex Crichton instance: InstanceId, 5958818b251SNick Fitzgerald module: &Module, 5968818b251SNick Fitzgerald ) -> Result<()> { 597d4e968c0SJamey Sharp let mut const_evaluator = ConstExprEvaluator::default(); 598d4e968c0SJamey Sharp 59972004aadSNick Fitzgerald for segment in module.table_initialization.segments.iter() { 6007d7b721eSTirth Patel let mut context = ConstEvalContext::new(instance); 601d4e968c0SJamey Sharp let start = unsafe { 602d4e968c0SJamey Sharp const_evaluator 6038818b251SNick Fitzgerald .eval(store, &mut context, &segment.offset) 604d4e968c0SJamey Sharp .expect("const expression should be valid") 605d4e968c0SJamey Sharp }; 606d4e968c0SJamey Sharp let start = usize::try_from(start.get_u32()).unwrap(); 60772004aadSNick Fitzgerald let end = start.checked_add(usize::try_from(segment.elements.len()).unwrap()); 60872004aadSNick Fitzgerald 609f021346eSAlex Crichton let table = store.instance_mut(instance).get_table(segment.table_index); 61072004aadSNick Fitzgerald match end { 611df69b9a7SLinwei Shang Some(end) if end <= table.size() => { 61272004aadSNick Fitzgerald // Initializer is in bounds 61372004aadSNick Fitzgerald } 61472004aadSNick Fitzgerald _ => { 61572004aadSNick Fitzgerald bail!("table out of bounds: elements segment does not fit") 61672004aadSNick Fitzgerald } 61772004aadSNick Fitzgerald } 61872004aadSNick Fitzgerald } 61972004aadSNick Fitzgerald 62072004aadSNick Fitzgerald Ok(()) 62172004aadSNick Fitzgerald } 62272004aadSNick Fitzgerald 623818966f3SNick Fitzgerald fn initialize_tables( 6248818b251SNick Fitzgerald store: &mut StoreOpaque, 625aad93a48SAlex Crichton context: &mut ConstEvalContext, 626818966f3SNick Fitzgerald const_evaluator: &mut ConstExprEvaluator, 627818966f3SNick Fitzgerald module: &Module, 628818966f3SNick Fitzgerald ) -> Result<()> { 62972004aadSNick Fitzgerald for (table, init) in module.table_initialization.initial_values.iter() { 63072004aadSNick Fitzgerald match init { 63172004aadSNick Fitzgerald // Tables are always initially null-initialized at this time 63272004aadSNick Fitzgerald TableInitialValue::Null { precomputed: _ } => {} 63372004aadSNick Fitzgerald 63472004aadSNick Fitzgerald TableInitialValue::Expr(expr) => { 63572004aadSNick Fitzgerald let raw = unsafe { 63672004aadSNick Fitzgerald const_evaluator 6378818b251SNick Fitzgerald .eval(store, context, expr) 63872004aadSNick Fitzgerald .expect("const expression should be valid") 63972004aadSNick Fitzgerald }; 64072004aadSNick Fitzgerald let idx = module.table_index(table); 6417a49e44fSAlex Crichton match module.tables[idx].ref_type.heap_type.top() { 64272004aadSNick Fitzgerald WasmHeapTopType::Extern => { 643ddfebe77SAlex Crichton store.gc_store_mut()?; 6449f81f226SAlex Crichton let (gc_store, instance) = 645ddfebe77SAlex Crichton store.optional_gc_store_and_instance_mut(context.instance); 646ddfebe77SAlex Crichton let gc_store = gc_store.unwrap(); 6479f81f226SAlex Crichton let table = instance.get_defined_table(table); 64872004aadSNick Fitzgerald let gc_ref = VMGcRef::from_raw_u32(raw.get_externref()); 64972004aadSNick Fitzgerald let items = (0..table.size()) 65072004aadSNick Fitzgerald .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r))); 6519034e101SAlex Crichton table.init_gc_refs(0, items)?; 65272004aadSNick Fitzgerald } 65372004aadSNick Fitzgerald 65472004aadSNick Fitzgerald WasmHeapTopType::Any => { 655ddfebe77SAlex Crichton store.gc_store_mut()?; 6569f81f226SAlex Crichton let (gc_store, instance) = 657ddfebe77SAlex Crichton store.optional_gc_store_and_instance_mut(context.instance); 658ddfebe77SAlex Crichton let gc_store = gc_store.unwrap(); 6599f81f226SAlex Crichton let table = instance.get_defined_table(table); 66072004aadSNick Fitzgerald let gc_ref = VMGcRef::from_raw_u32(raw.get_anyref()); 66172004aadSNick Fitzgerald let items = (0..table.size()) 66272004aadSNick Fitzgerald .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r))); 6639034e101SAlex Crichton table.init_gc_refs(0, items)?; 66472004aadSNick Fitzgerald } 66572004aadSNick Fitzgerald 666eaa4632eSChris Fallin WasmHeapTopType::Exn => { 667ddfebe77SAlex Crichton store.gc_store_mut()?; 668eaa4632eSChris Fallin let (gc_store, instance) = 669ddfebe77SAlex Crichton store.optional_gc_store_and_instance_mut(context.instance); 670ddfebe77SAlex Crichton let gc_store = gc_store.unwrap(); 671eaa4632eSChris Fallin let table = instance.get_defined_table(table); 672ddfebe77SAlex Crichton let gc_ref = VMGcRef::from_raw_u32(raw.get_exnref()); 673eaa4632eSChris Fallin let items = (0..table.size()) 674eaa4632eSChris Fallin .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r))); 675eaa4632eSChris Fallin table.init_gc_refs(0, items)?; 676eaa4632eSChris Fallin } 677eaa4632eSChris Fallin 67872004aadSNick Fitzgerald WasmHeapTopType::Func => { 6799f81f226SAlex Crichton let table = store 6809f81f226SAlex Crichton .instance_mut(context.instance) 6819f81f226SAlex Crichton .get_defined_table(table); 682c52b941eSAlex Crichton let funcref = NonNull::new(raw.get_funcref().cast::<VMFuncRef>()); 68372004aadSNick Fitzgerald let items = (0..table.size()).map(|_| funcref); 6849034e101SAlex Crichton table.init_func(0, items)?; 68572004aadSNick Fitzgerald } 686692490b8SDaniel Hillerström 687692490b8SDaniel Hillerström WasmHeapTopType::Cont => todo!(), // FIXME: #10248 stack switching support. 68872004aadSNick Fitzgerald } 68972004aadSNick Fitzgerald } 69072004aadSNick Fitzgerald } 69172004aadSNick Fitzgerald } 69272004aadSNick Fitzgerald 69372004aadSNick Fitzgerald // Note: if the module's table initializer state is in 69472004aadSNick Fitzgerald // FuncTable mode, we will lazily initialize tables based on 69572004aadSNick Fitzgerald // any statically-precomputed image of FuncIndexes, but there 69672004aadSNick Fitzgerald // may still be "leftover segments" that could not be 69772004aadSNick Fitzgerald // incorporated. So we have a unified handler here that 69872004aadSNick Fitzgerald // iterates over all segments (Segments mode) or leftover 69972004aadSNick Fitzgerald // segments (FuncTable mode) to initialize. 70072004aadSNick Fitzgerald for segment in module.table_initialization.segments.iter() { 701d4e968c0SJamey Sharp let start = unsafe { 702d4e968c0SJamey Sharp const_evaluator 7038818b251SNick Fitzgerald .eval(store, context, &segment.offset) 704d4e968c0SJamey Sharp .expect("const expression should be valid") 705d4e968c0SJamey Sharp }; 706aad93a48SAlex Crichton Instance::table_init_segment( 7078818b251SNick Fitzgerald store, 708aad93a48SAlex Crichton context.instance, 709818966f3SNick Fitzgerald const_evaluator, 71072004aadSNick Fitzgerald segment.table_index, 71172004aadSNick Fitzgerald &segment.elements, 712df69b9a7SLinwei Shang start.get_u64(), 71372004aadSNick Fitzgerald 0, 71472004aadSNick Fitzgerald segment.elements.len(), 7159034e101SAlex Crichton )?; 71672004aadSNick Fitzgerald } 71772004aadSNick Fitzgerald 71872004aadSNick Fitzgerald Ok(()) 71972004aadSNick Fitzgerald } 72072004aadSNick Fitzgerald 7218818b251SNick Fitzgerald fn get_memory_init_start( 7228818b251SNick Fitzgerald store: &mut StoreOpaque, 7238818b251SNick Fitzgerald init: &MemoryInitializer, 724aad93a48SAlex Crichton instance: InstanceId, 7258818b251SNick Fitzgerald ) -> Result<u64> { 7267d7b721eSTirth Patel let mut context = ConstEvalContext::new(instance); 727b44c23d1SJamey Sharp let mut const_evaluator = ConstExprEvaluator::default(); 7288818b251SNick Fitzgerald unsafe { const_evaluator.eval(store, &mut context, &init.offset) }.map(|v| { 729aad93a48SAlex Crichton match store.instance(instance).env_module().memories[init.memory_index].idx_type { 730df69b9a7SLinwei Shang wasmtime_environ::IndexType::I32 => v.get_u32().into(), 731df69b9a7SLinwei Shang wasmtime_environ::IndexType::I64 => v.get_u64(), 73272004aadSNick Fitzgerald } 733b44c23d1SJamey Sharp }) 73472004aadSNick Fitzgerald } 73572004aadSNick Fitzgerald 73672004aadSNick Fitzgerald fn check_memory_init_bounds( 7378818b251SNick Fitzgerald store: &mut StoreOpaque, 738aad93a48SAlex Crichton instance: InstanceId, 73972004aadSNick Fitzgerald initializers: &[MemoryInitializer], 74072004aadSNick Fitzgerald ) -> Result<()> { 74172004aadSNick Fitzgerald for init in initializers { 742aad93a48SAlex Crichton let memory = store.instance_mut(instance).get_memory(init.memory_index); 7438818b251SNick Fitzgerald let start = get_memory_init_start(store, init, instance)?; 74472004aadSNick Fitzgerald let end = usize::try_from(start) 74572004aadSNick Fitzgerald .ok() 74672004aadSNick Fitzgerald .and_then(|start| start.checked_add(init.data.len())); 74772004aadSNick Fitzgerald 74872004aadSNick Fitzgerald match end { 74972004aadSNick Fitzgerald Some(end) if end <= memory.current_length() => { 75072004aadSNick Fitzgerald // Initializer is in bounds 75172004aadSNick Fitzgerald } 75272004aadSNick Fitzgerald _ => { 75372004aadSNick Fitzgerald bail!("memory out of bounds: data segment does not fit") 75472004aadSNick Fitzgerald } 75572004aadSNick Fitzgerald } 75672004aadSNick Fitzgerald } 75772004aadSNick Fitzgerald 75872004aadSNick Fitzgerald Ok(()) 75972004aadSNick Fitzgerald } 76072004aadSNick Fitzgerald 761818966f3SNick Fitzgerald fn initialize_memories( 7628818b251SNick Fitzgerald store: &mut StoreOpaque, 763aad93a48SAlex Crichton context: &mut ConstEvalContext, 764818966f3SNick Fitzgerald const_evaluator: &mut ConstExprEvaluator, 765818966f3SNick Fitzgerald module: &Module, 766818966f3SNick Fitzgerald ) -> Result<()> { 76772004aadSNick Fitzgerald // Delegates to the `init_memory` method which is sort of a duplicate of 76872004aadSNick Fitzgerald // `instance.memory_init_segment` but is used at compile-time in other 76972004aadSNick Fitzgerald // contexts so is shared here to have only one method of memory 77072004aadSNick Fitzgerald // initialization. 77172004aadSNick Fitzgerald // 77272004aadSNick Fitzgerald // This call to `init_memory` notably implements all the bells and whistles 77372004aadSNick Fitzgerald // so errors only happen if an out-of-bounds segment is found, in which case 77472004aadSNick Fitzgerald // a trap is returned. 775b44c23d1SJamey Sharp 776aad93a48SAlex Crichton struct InitMemoryAtInstantiation<'a> { 777b44c23d1SJamey Sharp module: &'a Module, 7788818b251SNick Fitzgerald store: &'a mut StoreOpaque, 779aad93a48SAlex Crichton context: &'a mut ConstEvalContext, 780818966f3SNick Fitzgerald const_evaluator: &'a mut ConstExprEvaluator, 781b44c23d1SJamey Sharp } 782b44c23d1SJamey Sharp 783aad93a48SAlex Crichton impl InitMemory for InitMemoryAtInstantiation<'_> { 784bdd78422SNick Fitzgerald fn memory_size_in_bytes( 785bdd78422SNick Fitzgerald &mut self, 786bdd78422SNick Fitzgerald memory: wasmtime_environ::MemoryIndex, 787bdd78422SNick Fitzgerald ) -> Result<u64, SizeOverflow> { 788aad93a48SAlex Crichton let len = self 789aad93a48SAlex Crichton .store 790aad93a48SAlex Crichton .instance(self.context.instance) 791aad93a48SAlex Crichton .get_memory(memory) 792aad93a48SAlex Crichton .current_length(); 793bdd78422SNick Fitzgerald let len = u64::try_from(len).unwrap(); 794bdd78422SNick Fitzgerald Ok(len) 795b44c23d1SJamey Sharp } 796b44c23d1SJamey Sharp 797b44c23d1SJamey Sharp fn eval_offset( 798b44c23d1SJamey Sharp &mut self, 799b44c23d1SJamey Sharp memory: wasmtime_environ::MemoryIndex, 800b44c23d1SJamey Sharp expr: &wasmtime_environ::ConstExpr, 801b44c23d1SJamey Sharp ) -> Option<u64> { 8028818b251SNick Fitzgerald let val = unsafe { self.const_evaluator.eval(self.store, self.context, expr) } 803b44c23d1SJamey Sharp .expect("const expression should be valid"); 804df69b9a7SLinwei Shang Some( 805aad93a48SAlex Crichton match self 806aad93a48SAlex Crichton .store 807aad93a48SAlex Crichton .instance(self.context.instance) 808aad93a48SAlex Crichton .env_module() 809aad93a48SAlex Crichton .memories[memory] 810aad93a48SAlex Crichton .idx_type 811aad93a48SAlex Crichton { 812df69b9a7SLinwei Shang wasmtime_environ::IndexType::I32 => val.get_u32().into(), 813df69b9a7SLinwei Shang wasmtime_environ::IndexType::I64 => val.get_u64(), 814df69b9a7SLinwei Shang }, 815df69b9a7SLinwei Shang ) 816b44c23d1SJamey Sharp } 817b44c23d1SJamey Sharp 818b44c23d1SJamey Sharp fn write( 819b44c23d1SJamey Sharp &mut self, 820b44c23d1SJamey Sharp memory_index: wasmtime_environ::MemoryIndex, 821b44c23d1SJamey Sharp init: &wasmtime_environ::StaticMemoryInitializer, 822b44c23d1SJamey Sharp ) -> bool { 82372004aadSNick Fitzgerald // If this initializer applies to a defined memory but that memory 82472004aadSNick Fitzgerald // doesn't need initialization, due to something like copy-on-write 82572004aadSNick Fitzgerald // pre-initializing it via mmap magic, then this initializer can be 82672004aadSNick Fitzgerald // skipped entirely. 827aad93a48SAlex Crichton let instance = self.store.instance_mut(self.context.instance); 828b44c23d1SJamey Sharp if let Some(memory_index) = self.module.defined_memory_index(memory_index) { 829aad93a48SAlex Crichton if !instance.memories[memory_index].1.needs_init() { 83072004aadSNick Fitzgerald return true; 83172004aadSNick Fitzgerald } 83272004aadSNick Fitzgerald } 833aad93a48SAlex Crichton let memory = instance.get_memory(memory_index); 83472004aadSNick Fitzgerald 83572004aadSNick Fitzgerald unsafe { 836aad93a48SAlex Crichton let src = instance.wasm_data(init.data.clone()); 837c2717d18SAlex Crichton let offset = usize::try_from(init.offset).unwrap(); 838b86b9682SAlex Crichton let dst = memory.base.as_ptr().add(offset); 839c2717d18SAlex Crichton 840c2717d18SAlex Crichton assert!(offset + src.len() <= memory.current_length()); 841c2717d18SAlex Crichton 84272004aadSNick Fitzgerald // FIXME audit whether this is safe in the presence of shared 84372004aadSNick Fitzgerald // memory 84472004aadSNick Fitzgerald // (https://github.com/bytecodealliance/wasmtime/issues/4203). 84572004aadSNick Fitzgerald ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len()) 84672004aadSNick Fitzgerald } 84772004aadSNick Fitzgerald true 848b44c23d1SJamey Sharp } 849b44c23d1SJamey Sharp } 850b44c23d1SJamey Sharp 851b44c23d1SJamey Sharp let ok = module 852b44c23d1SJamey Sharp .memory_initialization 853b44c23d1SJamey Sharp .init_memory(&mut InitMemoryAtInstantiation { 854b44c23d1SJamey Sharp module, 8558818b251SNick Fitzgerald store, 856818966f3SNick Fitzgerald context, 857818966f3SNick Fitzgerald const_evaluator, 858b44c23d1SJamey Sharp }); 85972004aadSNick Fitzgerald if !ok { 8609034e101SAlex Crichton return Err(Trap::MemoryOutOfBounds.into()); 86172004aadSNick Fitzgerald } 86272004aadSNick Fitzgerald 86372004aadSNick Fitzgerald Ok(()) 86472004aadSNick Fitzgerald } 86572004aadSNick Fitzgerald 866aad93a48SAlex Crichton fn check_init_bounds(store: &mut StoreOpaque, instance: InstanceId, module: &Module) -> Result<()> { 8678818b251SNick Fitzgerald check_table_init_bounds(store, instance, module)?; 86872004aadSNick Fitzgerald 86972004aadSNick Fitzgerald match &module.memory_initialization { 87072004aadSNick Fitzgerald MemoryInitialization::Segmented(initializers) => { 8718818b251SNick Fitzgerald check_memory_init_bounds(store, instance, initializers)?; 87272004aadSNick Fitzgerald } 87372004aadSNick Fitzgerald // Statically validated already to have everything in-bounds. 87472004aadSNick Fitzgerald MemoryInitialization::Static { .. } => {} 87572004aadSNick Fitzgerald } 87672004aadSNick Fitzgerald 87772004aadSNick Fitzgerald Ok(()) 87872004aadSNick Fitzgerald } 87972004aadSNick Fitzgerald 880818966f3SNick Fitzgerald fn initialize_globals( 8818818b251SNick Fitzgerald store: &mut StoreOpaque, 882aad93a48SAlex Crichton context: &mut ConstEvalContext, 883818966f3SNick Fitzgerald const_evaluator: &mut ConstExprEvaluator, 884818966f3SNick Fitzgerald module: &Module, 885818966f3SNick Fitzgerald ) -> Result<()> { 886aad93a48SAlex Crichton assert!(core::ptr::eq( 887aad93a48SAlex Crichton &**store.instance(context.instance).env_module(), 888aad93a48SAlex Crichton module 889aad93a48SAlex Crichton )); 890818966f3SNick Fitzgerald 8918818b251SNick Fitzgerald let mut store = AutoAssertNoGc::new(store); 8928818b251SNick Fitzgerald 893818966f3SNick Fitzgerald for (index, init) in module.global_initializers.iter() { 894818966f3SNick Fitzgerald let raw = unsafe { 895818966f3SNick Fitzgerald const_evaluator 8968818b251SNick Fitzgerald .eval(&mut store, context, init) 897818966f3SNick Fitzgerald .expect("should be a valid const expr") 898818966f3SNick Fitzgerald }; 899818966f3SNick Fitzgerald 900aad93a48SAlex Crichton let instance = store.instance_mut(context.instance); 901aad93a48SAlex Crichton let to = instance.global_ptr(index); 902818966f3SNick Fitzgerald let wasm_ty = module.globals[module.global_index(index)].wasm_ty; 903818966f3SNick Fitzgerald 904818966f3SNick Fitzgerald #[cfg(feature = "wmemcheck")] 905b09b892cSAndrew Brown if index.as_u32() == 0 && wasm_ty == wasmtime_environ::WasmValType::I32 { 906aad93a48SAlex Crichton if let Some(wmemcheck) = instance.wmemcheck_state_mut() { 907818966f3SNick Fitzgerald let size = usize::try_from(raw.get_i32()).unwrap(); 908818966f3SNick Fitzgerald wmemcheck.set_stack_size(size); 909818966f3SNick Fitzgerald } 910818966f3SNick Fitzgerald } 911818966f3SNick Fitzgerald 912818966f3SNick Fitzgerald // This write is safe because we know we have the correct module for 913818966f3SNick Fitzgerald // this instance and its vmctx due to the assert above. 914818966f3SNick Fitzgerald unsafe { 915b86b9682SAlex Crichton to.write(VMGlobalDefinition::from_val_raw(&mut store, wasm_ty, raw)?); 916818966f3SNick Fitzgerald }; 917818966f3SNick Fitzgerald } 918818966f3SNick Fitzgerald Ok(()) 919818966f3SNick Fitzgerald } 920818966f3SNick Fitzgerald 921aad93a48SAlex Crichton pub fn initialize_instance( 9228818b251SNick Fitzgerald store: &mut StoreOpaque, 923aad93a48SAlex Crichton instance: InstanceId, 92472004aadSNick Fitzgerald module: &Module, 92572004aadSNick Fitzgerald is_bulk_memory: bool, 92672004aadSNick Fitzgerald ) -> Result<()> { 92772004aadSNick Fitzgerald // If bulk memory is not enabled, bounds check the data and element segments before 92872004aadSNick Fitzgerald // making any changes. With bulk memory enabled, initializers are processed 92972004aadSNick Fitzgerald // in-order and side effects are observed up to the point of an out-of-bounds 93072004aadSNick Fitzgerald // initializer, so the early checking is not desired. 93172004aadSNick Fitzgerald if !is_bulk_memory { 9328818b251SNick Fitzgerald check_init_bounds(store, instance, module)?; 93372004aadSNick Fitzgerald } 93472004aadSNick Fitzgerald 935818966f3SNick Fitzgerald let mut context = ConstEvalContext::new(instance); 936818966f3SNick Fitzgerald let mut const_evaluator = ConstExprEvaluator::default(); 93772004aadSNick Fitzgerald 9388818b251SNick Fitzgerald initialize_globals(store, &mut context, &mut const_evaluator, module)?; 9398818b251SNick Fitzgerald initialize_tables(store, &mut context, &mut const_evaluator, module)?; 9408818b251SNick Fitzgerald initialize_memories(store, &mut context, &mut const_evaluator, &module)?; 94172004aadSNick Fitzgerald 94272004aadSNick Fitzgerald Ok(()) 94372004aadSNick Fitzgerald } 94472004aadSNick Fitzgerald 94572004aadSNick Fitzgerald #[cfg(test)] 94672004aadSNick Fitzgerald mod tests { 94772004aadSNick Fitzgerald use super::*; 94872004aadSNick Fitzgerald 94972004aadSNick Fitzgerald #[test] 95072004aadSNick Fitzgerald fn allocator_traits_are_object_safe() { 95172004aadSNick Fitzgerald fn _instance_allocator(_: &dyn InstanceAllocatorImpl) {} 95272004aadSNick Fitzgerald fn _instance_allocator_ext(_: &dyn InstanceAllocator) {} 95372004aadSNick Fitzgerald } 95472004aadSNick Fitzgerald } 955