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;
8e1f50aadSAlex Crichton use crate::runtime::vm::{CompiledModuleId, ModuleRuntimeInfo};
9cc8d04f4SAlex Crichton use crate::store::{Asyncness, InstanceId, StoreOpaque, StoreResourceLimiter};
10aef5eeb5SAlex Crichton use crate::{OpaqueRootScope, Val};
1182ebbd5dSNick Fitzgerald use core::future::Future;
1282ebbd5dSNick Fitzgerald use core::pin::Pin;
13e012eedaSAlex Crichton use core::{mem, ptr};
1472004aadSNick Fitzgerald use wasmtime_environ::{
1572004aadSNick Fitzgerald     DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization,
169c44a9b4SNick Fitzgerald     MemoryInitializer, Module, SizeOverflow, TableInitialValue, Trap, VMOffsets,
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::{
35becdee57SLann     InstanceLimits, PoolConcurrencyLimitError, PoolingAllocatorMetrics, PoolingInstanceAllocator,
36e1f8b9b7SNick Fitzgerald     PoolingInstanceAllocatorConfig,
37e1f8b9b7SNick Fitzgerald };
3872004aadSNick Fitzgerald 
3972004aadSNick Fitzgerald /// Represents a request for a new runtime instance.
40155ea7fcSAlex Crichton pub struct InstanceAllocationRequest<'a, 'b> {
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 
55e1f50aadSAlex Crichton     /// The store that this instance is being allocated into.
56e1f50aadSAlex Crichton     pub store: &'a StoreOpaque,
5772004aadSNick Fitzgerald 
58e1f50aadSAlex Crichton     /// The store's resource limiter, if configured by the embedder.
59155ea7fcSAlex Crichton     pub limiter: Option<&'a mut StoreResourceLimiter<'b>>,
6072004aadSNick Fitzgerald }
6172004aadSNick Fitzgerald 
6272004aadSNick Fitzgerald /// The index of a memory allocation within an `InstanceAllocator`.
6372004aadSNick Fitzgerald #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
6472004aadSNick Fitzgerald pub struct MemoryAllocationIndex(u32);
6572004aadSNick Fitzgerald 
6672004aadSNick Fitzgerald impl Default for MemoryAllocationIndex {
default() -> Self6772004aadSNick Fitzgerald     fn default() -> Self {
6872004aadSNick Fitzgerald         // A default `MemoryAllocationIndex` that can be used with
6972004aadSNick Fitzgerald         // `InstanceAllocator`s that don't actually need indices.
7072004aadSNick Fitzgerald         MemoryAllocationIndex(u32::MAX)
7172004aadSNick Fitzgerald     }
7272004aadSNick Fitzgerald }
7372004aadSNick Fitzgerald 
7472004aadSNick Fitzgerald impl MemoryAllocationIndex {
7572004aadSNick Fitzgerald     /// Get the underlying index of this `MemoryAllocationIndex`.
7624620d9fSAlex Crichton     #[cfg(feature = "pooling-allocator")]
index(&self) -> usize7772004aadSNick Fitzgerald     pub fn index(&self) -> usize {
7872004aadSNick Fitzgerald         self.0 as usize
7972004aadSNick Fitzgerald     }
8072004aadSNick Fitzgerald }
8172004aadSNick Fitzgerald 
8272004aadSNick Fitzgerald /// The index of a table allocation within an `InstanceAllocator`.
8372004aadSNick Fitzgerald #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
8472004aadSNick Fitzgerald pub struct TableAllocationIndex(u32);
8572004aadSNick Fitzgerald 
8672004aadSNick Fitzgerald impl Default for TableAllocationIndex {
default() -> Self8772004aadSNick Fitzgerald     fn default() -> Self {
8872004aadSNick Fitzgerald         // A default `TableAllocationIndex` that can be used with
8972004aadSNick Fitzgerald         // `InstanceAllocator`s that don't actually need indices.
9072004aadSNick Fitzgerald         TableAllocationIndex(u32::MAX)
9172004aadSNick Fitzgerald     }
9272004aadSNick Fitzgerald }
9372004aadSNick Fitzgerald 
9472004aadSNick Fitzgerald impl TableAllocationIndex {
9572004aadSNick Fitzgerald     /// Get the underlying index of this `TableAllocationIndex`.
9624620d9fSAlex Crichton     #[cfg(feature = "pooling-allocator")]
index(&self) -> usize9772004aadSNick Fitzgerald     pub fn index(&self) -> usize {
9872004aadSNick Fitzgerald         self.0 as usize
9972004aadSNick Fitzgerald     }
10072004aadSNick Fitzgerald }
10172004aadSNick Fitzgerald 
10272004aadSNick Fitzgerald /// The index of a table allocation within an `InstanceAllocator`.
10372004aadSNick Fitzgerald #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
10472004aadSNick Fitzgerald pub struct GcHeapAllocationIndex(u32);
10572004aadSNick Fitzgerald 
10672004aadSNick Fitzgerald impl Default for GcHeapAllocationIndex {
default() -> Self10772004aadSNick Fitzgerald     fn default() -> Self {
10872004aadSNick Fitzgerald         // A default `GcHeapAllocationIndex` that can be used with
10972004aadSNick Fitzgerald         // `InstanceAllocator`s that don't actually need indices.
11072004aadSNick Fitzgerald         GcHeapAllocationIndex(u32::MAX)
11172004aadSNick Fitzgerald     }
11272004aadSNick Fitzgerald }
11372004aadSNick Fitzgerald 
11472004aadSNick Fitzgerald impl GcHeapAllocationIndex {
11572004aadSNick Fitzgerald     /// Get the underlying index of this `GcHeapAllocationIndex`.
index(&self) -> usize11672004aadSNick Fitzgerald     pub fn index(&self) -> usize {
11772004aadSNick Fitzgerald         self.0 as usize
11872004aadSNick Fitzgerald     }
11972004aadSNick Fitzgerald }
12072004aadSNick Fitzgerald 
12172004aadSNick Fitzgerald /// Trait that represents the hooks needed to implement an instance allocator.
12272004aadSNick Fitzgerald ///
12372004aadSNick Fitzgerald /// Implement this trait when implementing new instance allocators, but don't
12472004aadSNick Fitzgerald /// use this trait when you need an instance allocator. Instead use the
12572004aadSNick Fitzgerald /// `InstanceAllocator` trait for that, which has additional helper methods and
12672004aadSNick Fitzgerald /// a blanket implementation for all types that implement this trait.
12772004aadSNick Fitzgerald ///
12872004aadSNick Fitzgerald /// # Safety
12972004aadSNick Fitzgerald ///
13072004aadSNick Fitzgerald /// This trait is unsafe as it requires knowledge of Wasmtime's runtime
13172004aadSNick Fitzgerald /// internals to implement correctly.
132f8177c20SAlex Crichton pub unsafe trait InstanceAllocator: Send + Sync {
13372004aadSNick Fitzgerald     /// Validate whether a component (including all of its contained core
13472004aadSNick Fitzgerald     /// modules) is allocatable by this instance allocator.
13572004aadSNick Fitzgerald     #[cfg(feature = "component-model")]
validate_component<'a>( &self, component: &Component, offsets: &VMComponentOffsets<HostPtr>, get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module, ) -> Result<()>136f8177c20SAlex Crichton     fn validate_component<'a>(
13772004aadSNick Fitzgerald         &self,
13872004aadSNick Fitzgerald         component: &Component,
13972004aadSNick Fitzgerald         offsets: &VMComponentOffsets<HostPtr>,
14072004aadSNick Fitzgerald         get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module,
14172004aadSNick Fitzgerald     ) -> Result<()>;
14272004aadSNick Fitzgerald 
14372004aadSNick Fitzgerald     /// Validate whether a module is allocatable by this instance allocator.
validate_module(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()>144f8177c20SAlex Crichton     fn validate_module(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()>;
14572004aadSNick Fitzgerald 
146c22b3cb9SNick Fitzgerald     /// Validate whether a memory is allocatable by this instance allocator.
147c22b3cb9SNick Fitzgerald     #[cfg(feature = "gc")]
validate_memory(&self, memory: &wasmtime_environ::Memory) -> Result<()>148f8177c20SAlex Crichton     fn validate_memory(&self, memory: &wasmtime_environ::Memory) -> Result<()>;
149c22b3cb9SNick Fitzgerald 
15072004aadSNick Fitzgerald     /// Increment the count of concurrent component instances that are currently
15172004aadSNick Fitzgerald     /// allocated, if applicable.
15272004aadSNick Fitzgerald     ///
15372004aadSNick Fitzgerald     /// Not all instance allocators will have limits for the maximum number of
15472004aadSNick Fitzgerald     /// concurrent component instances that can be live at the same time, and
15572004aadSNick Fitzgerald     /// these allocators may implement this method with a no-op.
15672004aadSNick Fitzgerald     //
15772004aadSNick Fitzgerald     // Note: It would be nice to have an associated type that on construction
15872004aadSNick Fitzgerald     // does the increment and on drop does the decrement but there are two
15972004aadSNick Fitzgerald     // problems with this:
16072004aadSNick Fitzgerald     //
16172004aadSNick Fitzgerald     // 1. This trait's implementations are always used as trait objects, and
16272004aadSNick Fitzgerald     //    associated types are not object safe.
16372004aadSNick Fitzgerald     //
16472004aadSNick Fitzgerald     // 2. We would want a parameterized `Drop` implementation so that we could
165f8177c20SAlex Crichton     //    pass in the `InstanceAllocator` on drop, but this doesn't exist in
16672004aadSNick Fitzgerald     //    Rust. Therefore, we would be forced to add reference counting and
16772004aadSNick Fitzgerald     //    stuff like that to keep a handle on the instance allocator from this
16872004aadSNick Fitzgerald     //    theoretical type. That's a bummer.
169ef921e81SAlex Crichton     #[cfg(feature = "component-model")]
increment_component_instance_count(&self) -> Result<()>17072004aadSNick Fitzgerald     fn increment_component_instance_count(&self) -> Result<()>;
17172004aadSNick Fitzgerald 
17272004aadSNick Fitzgerald     /// The dual of `increment_component_instance_count`.
173ef921e81SAlex Crichton     #[cfg(feature = "component-model")]
decrement_component_instance_count(&self)17472004aadSNick Fitzgerald     fn decrement_component_instance_count(&self);
17572004aadSNick Fitzgerald 
17672004aadSNick Fitzgerald     /// Increment the count of concurrent core module instances that are
17772004aadSNick Fitzgerald     /// currently allocated, if applicable.
17872004aadSNick Fitzgerald     ///
17972004aadSNick Fitzgerald     /// Not all instance allocators will have limits for the maximum number of
18072004aadSNick Fitzgerald     /// concurrent core module instances that can be live at the same time, and
18172004aadSNick Fitzgerald     /// these allocators may implement this method with a no-op.
increment_core_instance_count(&self) -> Result<()>18272004aadSNick Fitzgerald     fn increment_core_instance_count(&self) -> Result<()>;
18372004aadSNick Fitzgerald 
18472004aadSNick Fitzgerald     /// The dual of `increment_core_instance_count`.
decrement_core_instance_count(&self)18572004aadSNick Fitzgerald     fn decrement_core_instance_count(&self);
18672004aadSNick Fitzgerald 
18772004aadSNick Fitzgerald     /// Allocate a memory for an instance.
18882ebbd5dSNick Fitzgerald     ///
18982ebbd5dSNick Fitzgerald     /// Returns `Err(OutOfMemory)` if boxing the future fails. The inner
19082ebbd5dSNick Fitzgerald     /// `Result` covers other allocation errors (e.g. resource limits).
allocate_memory<'a, 'b: 'a, 'c: 'a>( &'a self, request: &'a mut InstanceAllocationRequest<'b, 'c>, ty: &'a wasmtime_environ::Memory, memory_index: Option<DefinedMemoryIndex>, ) -> Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>>19182ebbd5dSNick Fitzgerald     fn allocate_memory<'a, 'b: 'a, 'c: 'a>(
19282ebbd5dSNick Fitzgerald         &'a self,
19382ebbd5dSNick Fitzgerald         request: &'a mut InstanceAllocationRequest<'b, 'c>,
19482ebbd5dSNick Fitzgerald         ty: &'a wasmtime_environ::Memory,
195c22b3cb9SNick Fitzgerald         memory_index: Option<DefinedMemoryIndex>,
1969bc302adSAlex Crichton     ) -> Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>>;
19772004aadSNick Fitzgerald 
19872004aadSNick Fitzgerald     /// Deallocate an instance's previously allocated memory.
19972004aadSNick Fitzgerald     ///
20072004aadSNick Fitzgerald     /// # Unsafety
20172004aadSNick Fitzgerald     ///
20272004aadSNick Fitzgerald     /// The memory must have previously been allocated by
20372004aadSNick Fitzgerald     /// `Self::allocate_memory`, be at the given index, and must currently be
20472004aadSNick Fitzgerald     /// allocated. It must never be used again.
deallocate_memory( &self, memory_index: Option<DefinedMemoryIndex>, allocation_index: MemoryAllocationIndex, memory: Memory, )20572004aadSNick Fitzgerald     unsafe fn deallocate_memory(
20672004aadSNick Fitzgerald         &self,
207c22b3cb9SNick Fitzgerald         memory_index: Option<DefinedMemoryIndex>,
20872004aadSNick Fitzgerald         allocation_index: MemoryAllocationIndex,
20972004aadSNick Fitzgerald         memory: Memory,
21072004aadSNick Fitzgerald     );
21172004aadSNick Fitzgerald 
21272004aadSNick Fitzgerald     /// Allocate a table for an instance.
21382ebbd5dSNick Fitzgerald     ///
21482ebbd5dSNick Fitzgerald     /// Returns `Err(OutOfMemory)` if boxing the future fails. The inner
21582ebbd5dSNick Fitzgerald     /// `Result` covers other allocation errors (e.g. resource limits).
allocate_table<'a, 'b: 'a, 'c: 'a>( &'a self, req: &'a mut InstanceAllocationRequest<'b, 'c>, table: &'a wasmtime_environ::Table, table_index: DefinedTableIndex, ) -> Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>>21682ebbd5dSNick Fitzgerald     fn allocate_table<'a, 'b: 'a, 'c: 'a>(
21782ebbd5dSNick Fitzgerald         &'a self,
21882ebbd5dSNick Fitzgerald         req: &'a mut InstanceAllocationRequest<'b, 'c>,
21982ebbd5dSNick Fitzgerald         table: &'a wasmtime_environ::Table,
22072004aadSNick Fitzgerald         table_index: DefinedTableIndex,
2219bc302adSAlex Crichton     ) -> Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>>;
22272004aadSNick Fitzgerald 
22372004aadSNick Fitzgerald     /// Deallocate an instance's previously allocated table.
22472004aadSNick Fitzgerald     ///
22572004aadSNick Fitzgerald     /// # Unsafety
22672004aadSNick Fitzgerald     ///
22772004aadSNick Fitzgerald     /// The table must have previously been allocated by `Self::allocate_table`,
22872004aadSNick Fitzgerald     /// be at the given index, and must currently be allocated. It must never be
22972004aadSNick Fitzgerald     /// used again.
deallocate_table( &self, table_index: DefinedTableIndex, allocation_index: TableAllocationIndex, table: Table, )23072004aadSNick Fitzgerald     unsafe fn deallocate_table(
23172004aadSNick Fitzgerald         &self,
23272004aadSNick Fitzgerald         table_index: DefinedTableIndex,
23372004aadSNick Fitzgerald         allocation_index: TableAllocationIndex,
23472004aadSNick Fitzgerald         table: Table,
23572004aadSNick Fitzgerald     );
23672004aadSNick Fitzgerald 
23772004aadSNick Fitzgerald     /// Allocates a fiber stack for calling async functions on.
23872004aadSNick Fitzgerald     #[cfg(feature = "async")]
allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack>23972004aadSNick Fitzgerald     fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack>;
24072004aadSNick Fitzgerald 
24172004aadSNick Fitzgerald     /// Deallocates a fiber stack that was previously allocated with
24272004aadSNick Fitzgerald     /// `allocate_fiber_stack`.
24372004aadSNick Fitzgerald     ///
24472004aadSNick Fitzgerald     /// # Safety
24572004aadSNick Fitzgerald     ///
24672004aadSNick Fitzgerald     /// The provided stack is required to have been allocated with
24772004aadSNick Fitzgerald     /// `allocate_fiber_stack`.
24872004aadSNick Fitzgerald     #[cfg(feature = "async")]
deallocate_fiber_stack(&self, stack: wasmtime_fiber::FiberStack)249e1f8b9b7SNick Fitzgerald     unsafe fn deallocate_fiber_stack(&self, stack: wasmtime_fiber::FiberStack);
25072004aadSNick Fitzgerald 
25172004aadSNick Fitzgerald     /// Allocate a GC heap for allocating Wasm GC objects within.
25272004aadSNick Fitzgerald     #[cfg(feature = "gc")]
allocate_gc_heap( &self, engine: &crate::Engine, gc_runtime: &dyn GcRuntime, memory_alloc_index: MemoryAllocationIndex, memory: Memory, ) -> Result<(GcHeapAllocationIndex, Box<dyn GcHeap>)>25372004aadSNick Fitzgerald     fn allocate_gc_heap(
25472004aadSNick Fitzgerald         &self,
255eafe7439SNick Fitzgerald         engine: &crate::Engine,
25672004aadSNick Fitzgerald         gc_runtime: &dyn GcRuntime,
257c22b3cb9SNick Fitzgerald         memory_alloc_index: MemoryAllocationIndex,
258c22b3cb9SNick Fitzgerald         memory: Memory,
25972004aadSNick Fitzgerald     ) -> Result<(GcHeapAllocationIndex, Box<dyn GcHeap>)>;
26072004aadSNick Fitzgerald 
26172004aadSNick Fitzgerald     /// Deallocate a GC heap that was previously allocated with
26272004aadSNick Fitzgerald     /// `allocate_gc_heap`.
26372004aadSNick Fitzgerald     #[cfg(feature = "gc")]
264c22b3cb9SNick Fitzgerald     #[must_use = "it is the caller's responsibility to deallocate the GC heap's underlying memory \
265c22b3cb9SNick Fitzgerald                   storage after the GC heap is deallocated"]
deallocate_gc_heap( &self, allocation_index: GcHeapAllocationIndex, gc_heap: Box<dyn GcHeap>, ) -> (MemoryAllocationIndex, Memory)266c22b3cb9SNick Fitzgerald     fn deallocate_gc_heap(
267c22b3cb9SNick Fitzgerald         &self,
268c22b3cb9SNick Fitzgerald         allocation_index: GcHeapAllocationIndex,
269c22b3cb9SNick Fitzgerald         gc_heap: Box<dyn GcHeap>,
270c22b3cb9SNick Fitzgerald     ) -> (MemoryAllocationIndex, Memory);
27172004aadSNick Fitzgerald 
27272004aadSNick Fitzgerald     /// Purges all lingering resources related to `module` from within this
27372004aadSNick Fitzgerald     /// allocator.
27472004aadSNick Fitzgerald     ///
27572004aadSNick Fitzgerald     /// Primarily present for the pooling allocator to remove mappings of
27672004aadSNick Fitzgerald     /// this module from slots in linear memory.
purge_module(&self, module: CompiledModuleId)27772004aadSNick Fitzgerald     fn purge_module(&self, module: CompiledModuleId);
27872004aadSNick Fitzgerald 
27972004aadSNick Fitzgerald     /// Use the next available protection key.
28072004aadSNick Fitzgerald     ///
28172004aadSNick Fitzgerald     /// The pooling allocator can use memory protection keys (MPK) for
28272004aadSNick Fitzgerald     /// compressing the guard regions protecting against OOB. Each
28372004aadSNick Fitzgerald     /// pool-allocated store needs its own key.
next_available_pkey(&self) -> Option<ProtectionKey>28472004aadSNick Fitzgerald     fn next_available_pkey(&self) -> Option<ProtectionKey>;
28572004aadSNick Fitzgerald 
28672004aadSNick Fitzgerald     /// Restrict access to memory regions protected by `pkey`.
28772004aadSNick Fitzgerald     ///
28872004aadSNick Fitzgerald     /// This is useful for the pooling allocator, which can use memory
28972004aadSNick Fitzgerald     /// protection keys (MPK). Note: this may still allow access to other
29072004aadSNick Fitzgerald     /// protection keys, such as the default kernel key; see implementations of
29172004aadSNick Fitzgerald     /// this.
restrict_to_pkey(&self, pkey: ProtectionKey)29272004aadSNick Fitzgerald     fn restrict_to_pkey(&self, pkey: ProtectionKey);
29372004aadSNick Fitzgerald 
29472004aadSNick Fitzgerald     /// Allow access to memory regions protected by any protection key.
allow_all_pkeys(&self)29572004aadSNick Fitzgerald     fn allow_all_pkeys(&self);
296becdee57SLann 
297becdee57SLann     /// Returns `Some(&PoolingInstanceAllocator)` if this is one.
298becdee57SLann     #[cfg(feature = "pooling-allocator")]
as_pooling(&self) -> Option<&PoolingInstanceAllocator>299becdee57SLann     fn as_pooling(&self) -> Option<&PoolingInstanceAllocator> {
300becdee57SLann         None
301becdee57SLann     }
30272004aadSNick Fitzgerald }
30372004aadSNick Fitzgerald 
304f8177c20SAlex Crichton impl dyn InstanceAllocator + '_ {
30572004aadSNick Fitzgerald     /// Allocates a fresh `InstanceHandle` for the `req` given.
30672004aadSNick Fitzgerald     ///
30772004aadSNick Fitzgerald     /// This will allocate memories and tables internally from this allocator
30872004aadSNick Fitzgerald     /// and weave that altogether into a final and complete `InstanceHandle`
30972004aadSNick Fitzgerald     /// ready to be registered with a store.
31072004aadSNick Fitzgerald     ///
31172004aadSNick Fitzgerald     /// Note that the returned instance must still have `.initialize(..)` called
31272004aadSNick Fitzgerald     /// on it to complete the instantiation process.
31372004aadSNick Fitzgerald     ///
31488079b4fSAlex Crichton     /// # Safety
31572004aadSNick Fitzgerald     ///
31688079b4fSAlex Crichton     /// The `request` provided must be valid, e.g. the imports within are
31788079b4fSAlex Crichton     /// correctly sized/typed for the instance being created.
allocate_module( &self, mut request: InstanceAllocationRequest<'_, '_>, ) -> Result<InstanceHandle>318e1f50aadSAlex Crichton     pub(crate) async unsafe fn allocate_module(
31972004aadSNick Fitzgerald         &self,
320155ea7fcSAlex Crichton         mut request: InstanceAllocationRequest<'_, '_>,
32172004aadSNick Fitzgerald     ) -> Result<InstanceHandle> {
3222bdae8b6SNick Fitzgerald         let module = request.runtime_info.env_module();
32372004aadSNick Fitzgerald 
324f8177c20SAlex Crichton         if cfg!(debug_assertions) {
325f8177c20SAlex Crichton             InstanceAllocator::validate_module(self, module, request.runtime_info.offsets())
32672004aadSNick Fitzgerald                 .expect("module should have already been validated before allocation");
327f8177c20SAlex Crichton         }
32872004aadSNick Fitzgerald 
32972004aadSNick Fitzgerald         self.increment_core_instance_count()?;
33072004aadSNick Fitzgerald 
3312a7f0653SAlex Crichton         let num_defined_memories = module.num_defined_memories();
3327a49e44fSAlex Crichton         let num_defined_tables = module.num_defined_tables();
33372004aadSNick Fitzgerald 
33494a8bb8cSAlex Crichton         let mut guard = DeallocateOnDrop {
33594a8bb8cSAlex Crichton             run_deallocate: true,
3369c44a9b4SNick Fitzgerald             memories: TryPrimaryMap::with_capacity(num_defined_memories)?,
3379c44a9b4SNick Fitzgerald             tables: TryPrimaryMap::with_capacity(num_defined_tables)?,
33894a8bb8cSAlex Crichton             allocator: self,
33994a8bb8cSAlex Crichton         };
34094a8bb8cSAlex Crichton 
341e1f50aadSAlex Crichton         self.allocate_memories(&mut request, &mut guard.memories)
342e1f50aadSAlex Crichton             .await?;
343e1f50aadSAlex Crichton         self.allocate_tables(&mut request, &mut guard.tables)
344e1f50aadSAlex Crichton             .await?;
34594a8bb8cSAlex Crichton         guard.run_deallocate = false;
34688079b4fSAlex Crichton         // SAFETY: memories/tables were just allocated from the store within
34788079b4fSAlex Crichton         // `request` and this function's own contract requires that the
34888079b4fSAlex Crichton         // imports are valid.
34994a8bb8cSAlex Crichton         return unsafe {
35094a8bb8cSAlex Crichton             Ok(Instance::new(
35194a8bb8cSAlex Crichton                 request,
35294a8bb8cSAlex Crichton                 mem::take(&mut guard.memories),
35394a8bb8cSAlex Crichton                 mem::take(&mut guard.tables),
354a465eabfSNick Fitzgerald             )?)
35594a8bb8cSAlex Crichton         };
35694a8bb8cSAlex Crichton 
35794a8bb8cSAlex Crichton         struct DeallocateOnDrop<'a> {
35894a8bb8cSAlex Crichton             run_deallocate: bool,
3599c44a9b4SNick Fitzgerald             memories: TryPrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
3609c44a9b4SNick Fitzgerald             tables: TryPrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
36194a8bb8cSAlex Crichton             allocator: &'a (dyn InstanceAllocator + 'a),
36294a8bb8cSAlex Crichton         }
36394a8bb8cSAlex Crichton 
36494a8bb8cSAlex Crichton         impl Drop for DeallocateOnDrop<'_> {
36594a8bb8cSAlex Crichton             fn drop(&mut self) {
36694a8bb8cSAlex Crichton                 if !self.run_deallocate {
36794a8bb8cSAlex Crichton                     return;
36894a8bb8cSAlex Crichton                 }
369b052dee0SAlex Crichton                 // SAFETY: these were previously allocated by this allocator
370b052dee0SAlex Crichton                 unsafe {
37194a8bb8cSAlex Crichton                     self.allocator.deallocate_memories(&mut self.memories);
37294a8bb8cSAlex Crichton                     self.allocator.deallocate_tables(&mut self.tables);
373b052dee0SAlex Crichton                 }
37494a8bb8cSAlex Crichton                 self.allocator.decrement_core_instance_count();
37572004aadSNick Fitzgerald             }
37672004aadSNick Fitzgerald         }
37772004aadSNick Fitzgerald     }
37872004aadSNick Fitzgerald 
37972004aadSNick Fitzgerald     /// Deallocates the provided instance.
38072004aadSNick Fitzgerald     ///
38172004aadSNick Fitzgerald     /// This will null-out the pointer within `handle` and otherwise reclaim
38272004aadSNick Fitzgerald     /// resources such as tables, memories, and the instance memory itself.
38372004aadSNick Fitzgerald     ///
38472004aadSNick Fitzgerald     /// # Unsafety
38572004aadSNick Fitzgerald     ///
38672004aadSNick Fitzgerald     /// The instance must have previously been allocated by `Self::allocate`.
deallocate_module(&self, handle: &mut InstanceHandle)387f8177c20SAlex Crichton     pub(crate) unsafe fn deallocate_module(&self, handle: &mut InstanceHandle) {
388b052dee0SAlex Crichton         // SAFETY: the contract of `deallocate_*` is itself a contract of this
389b052dee0SAlex Crichton         // function, that the memories/tables were previously allocated from
390b052dee0SAlex Crichton         // here.
391b052dee0SAlex Crichton         unsafe {
392aad93a48SAlex Crichton             self.deallocate_memories(handle.get_mut().memories_mut());
393aad93a48SAlex Crichton             self.deallocate_tables(handle.get_mut().tables_mut());
394b052dee0SAlex Crichton         }
39572004aadSNick Fitzgerald 
39672004aadSNick Fitzgerald         self.decrement_core_instance_count();
39772004aadSNick Fitzgerald     }
39872004aadSNick Fitzgerald 
39972004aadSNick Fitzgerald     /// Allocate the memories for the given instance allocation request, pushing
40072004aadSNick Fitzgerald     /// them into `memories`.
allocate_memories( &self, request: &mut InstanceAllocationRequest<'_, '_>, memories: &mut TryPrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, ) -> Result<()>4019bc302adSAlex Crichton     async fn allocate_memories(
4029bc302adSAlex Crichton         &self,
4039bc302adSAlex Crichton         request: &mut InstanceAllocationRequest<'_, '_>,
4049c44a9b4SNick Fitzgerald         memories: &mut TryPrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
40572004aadSNick Fitzgerald     ) -> Result<()> {
4062bdae8b6SNick Fitzgerald         let module = request.runtime_info.env_module();
40772004aadSNick Fitzgerald 
408f8177c20SAlex Crichton         if cfg!(debug_assertions) {
409f8177c20SAlex Crichton             InstanceAllocator::validate_module(self, module, request.runtime_info.offsets())
41072004aadSNick Fitzgerald                 .expect("module should have already been validated before allocation");
411f8177c20SAlex Crichton         }
41272004aadSNick Fitzgerald 
4132a7f0653SAlex Crichton         for (memory_index, ty) in module.memories.iter().skip(module.num_imported_memories) {
41472004aadSNick Fitzgerald             let memory_index = module
41572004aadSNick Fitzgerald                 .defined_memory_index(memory_index)
41672004aadSNick Fitzgerald                 .expect("should be a defined memory since we skipped imported ones");
41772004aadSNick Fitzgerald 
418e1f50aadSAlex Crichton             let memory = self
4199bc302adSAlex Crichton                 .allocate_memory(request, ty, Some(memory_index))
420e1f50aadSAlex Crichton                 .await?;
4219c44a9b4SNick Fitzgerald             memories.push(memory)?;
42272004aadSNick Fitzgerald         }
42372004aadSNick Fitzgerald 
42472004aadSNick Fitzgerald         Ok(())
42572004aadSNick Fitzgerald     }
42672004aadSNick Fitzgerald 
42772004aadSNick Fitzgerald     /// Deallocate all the memories in the given primary map.
42872004aadSNick Fitzgerald     ///
42972004aadSNick Fitzgerald     /// # Unsafety
43072004aadSNick Fitzgerald     ///
43172004aadSNick Fitzgerald     /// The memories must have previously been allocated by
43272004aadSNick Fitzgerald     /// `Self::allocate_memories`.
deallocate_memories( &self, memories: &mut TryPrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, )43372004aadSNick Fitzgerald     unsafe fn deallocate_memories(
43472004aadSNick Fitzgerald         &self,
4359c44a9b4SNick Fitzgerald         memories: &mut TryPrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
43672004aadSNick Fitzgerald     ) {
43772004aadSNick Fitzgerald         for (memory_index, (allocation_index, memory)) in mem::take(memories) {
43872004aadSNick Fitzgerald             // Because deallocating memory is infallible, we don't need to worry
43972004aadSNick Fitzgerald             // about leaking subsequent memories if the first memory failed to
44072004aadSNick Fitzgerald             // deallocate. If deallocating memory ever becomes fallible, we will
44172004aadSNick Fitzgerald             // need to be careful here!
442b052dee0SAlex Crichton             //
443b052dee0SAlex Crichton             // SAFETY: the unsafe contract here is the same as the unsafe
444b052dee0SAlex Crichton             // contract of this function, that the memories were previously
445b052dee0SAlex Crichton             // allocated by this allocator.
446b052dee0SAlex Crichton             unsafe {
447c22b3cb9SNick Fitzgerald                 self.deallocate_memory(Some(memory_index), allocation_index, memory);
44872004aadSNick Fitzgerald             }
44972004aadSNick Fitzgerald         }
450b052dee0SAlex Crichton     }
45172004aadSNick Fitzgerald 
45272004aadSNick Fitzgerald     /// Allocate tables for the given instance allocation request, pushing them
45372004aadSNick Fitzgerald     /// into `tables`.
allocate_tables( &self, request: &mut InstanceAllocationRequest<'_, '_>, tables: &mut TryPrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, ) -> Result<()>4549bc302adSAlex Crichton     async fn allocate_tables(
4559bc302adSAlex Crichton         &self,
4569bc302adSAlex Crichton         request: &mut InstanceAllocationRequest<'_, '_>,
4579c44a9b4SNick Fitzgerald         tables: &mut TryPrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
45872004aadSNick Fitzgerald     ) -> Result<()> {
4592bdae8b6SNick Fitzgerald         let module = request.runtime_info.env_module();
46072004aadSNick Fitzgerald 
461f8177c20SAlex Crichton         if cfg!(debug_assertions) {
462f8177c20SAlex Crichton             InstanceAllocator::validate_module(self, module, request.runtime_info.offsets())
46372004aadSNick Fitzgerald                 .expect("module should have already been validated before allocation");
464f8177c20SAlex Crichton         }
46572004aadSNick Fitzgerald 
4667a49e44fSAlex Crichton         for (index, table) in module.tables.iter().skip(module.num_imported_tables) {
46772004aadSNick Fitzgerald             let def_index = module
46872004aadSNick Fitzgerald                 .defined_table_index(index)
46972004aadSNick Fitzgerald                 .expect("should be a defined table since we skipped imported ones");
47072004aadSNick Fitzgerald 
4719bc302adSAlex Crichton             let table = self.allocate_table(request, table, def_index).await?;
4729c44a9b4SNick Fitzgerald             tables.push(table)?;
47372004aadSNick Fitzgerald         }
47472004aadSNick Fitzgerald 
47572004aadSNick Fitzgerald         Ok(())
47672004aadSNick Fitzgerald     }
47772004aadSNick Fitzgerald 
47872004aadSNick Fitzgerald     /// Deallocate all the tables in the given primary map.
47972004aadSNick Fitzgerald     ///
48072004aadSNick Fitzgerald     /// # Unsafety
48172004aadSNick Fitzgerald     ///
48272004aadSNick Fitzgerald     /// The tables must have previously been allocated by
48372004aadSNick Fitzgerald     /// `Self::allocate_tables`.
deallocate_tables( &self, tables: &mut TryPrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, )48472004aadSNick Fitzgerald     unsafe fn deallocate_tables(
48572004aadSNick Fitzgerald         &self,
4869c44a9b4SNick Fitzgerald         tables: &mut TryPrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
48772004aadSNick Fitzgerald     ) {
48872004aadSNick Fitzgerald         for (table_index, (allocation_index, table)) in mem::take(tables) {
489b052dee0SAlex Crichton             // SAFETY: the tables here were allocated from this allocator per
490b052dee0SAlex Crichton             // the contract on this function itself.
491b052dee0SAlex Crichton             unsafe {
49272004aadSNick Fitzgerald                 self.deallocate_table(table_index, allocation_index, table);
49372004aadSNick Fitzgerald             }
49472004aadSNick Fitzgerald         }
49572004aadSNick Fitzgerald     }
496b052dee0SAlex Crichton }
49772004aadSNick Fitzgerald 
check_table_init_bounds( store: &mut StoreOpaque, instance: InstanceId, module: &Module, context: &mut ConstEvalContext, const_evaluator: &mut ConstExprEvaluator, ) -> Result<()>4988818b251SNick Fitzgerald fn check_table_init_bounds(
4998818b251SNick Fitzgerald     store: &mut StoreOpaque,
500aad93a48SAlex Crichton     instance: InstanceId,
5018818b251SNick Fitzgerald     module: &Module,
502cc8d04f4SAlex Crichton     context: &mut ConstEvalContext,
503cc8d04f4SAlex Crichton     const_evaluator: &mut ConstExprEvaluator,
5048818b251SNick Fitzgerald ) -> Result<()> {
505aef5eeb5SAlex Crichton     let mut store = OpaqueRootScope::new(store);
506d4e968c0SJamey Sharp 
50772004aadSNick Fitzgerald     for segment in module.table_initialization.segments.iter() {
508d1397130SAlex Crichton         let start = const_evaluator
509cc8d04f4SAlex Crichton             .eval_int(&mut store, context, &segment.offset)
510d1397130SAlex Crichton             .expect("const expression should be valid");
5119c3ed199SAlex Crichton         let start = get_index(start, module.tables[segment.table_index].idx_type);
5129c3ed199SAlex Crichton         let end = start.checked_add(segment.elements.len());
51372004aadSNick Fitzgerald 
514f021346eSAlex Crichton         let table = store.instance_mut(instance).get_table(segment.table_index);
51572004aadSNick Fitzgerald         match end {
5169c3ed199SAlex Crichton             Some(end) if end <= u64::try_from(table.size())? => {
51772004aadSNick Fitzgerald                 // Initializer is in bounds
51872004aadSNick Fitzgerald             }
51972004aadSNick Fitzgerald             _ => {
520*517c0287SAlex Crichton                 bail!(Trap::TableOutOfBounds);
52172004aadSNick Fitzgerald             }
52272004aadSNick Fitzgerald         }
52372004aadSNick Fitzgerald     }
52472004aadSNick Fitzgerald 
52572004aadSNick Fitzgerald     Ok(())
52672004aadSNick Fitzgerald }
52772004aadSNick Fitzgerald 
initialize_tables( store: &mut StoreOpaque, mut limiter: Option<&mut StoreResourceLimiter<'_>>, context: &mut ConstEvalContext, const_evaluator: &mut ConstExprEvaluator, module: &Module, ) -> Result<()>528d1397130SAlex Crichton async fn initialize_tables(
5298818b251SNick Fitzgerald     store: &mut StoreOpaque,
530155ea7fcSAlex Crichton     mut limiter: Option<&mut StoreResourceLimiter<'_>>,
531aad93a48SAlex Crichton     context: &mut ConstEvalContext,
532818966f3SNick Fitzgerald     const_evaluator: &mut ConstExprEvaluator,
533818966f3SNick Fitzgerald     module: &Module,
534818966f3SNick Fitzgerald ) -> Result<()> {
535aef5eeb5SAlex Crichton     let mut store = OpaqueRootScope::new(store);
53672004aadSNick Fitzgerald     for (table, init) in module.table_initialization.initial_values.iter() {
53772004aadSNick Fitzgerald         match init {
53872004aadSNick Fitzgerald             // Tables are always initially null-initialized at this time
53972004aadSNick Fitzgerald             TableInitialValue::Null { precomputed: _ } => {}
54072004aadSNick Fitzgerald 
54172004aadSNick Fitzgerald             TableInitialValue::Expr(expr) => {
542d1397130SAlex Crichton                 let init = const_evaluator
543155ea7fcSAlex Crichton                     .eval(&mut store, limiter.as_deref_mut(), context, expr)
54479419198SAlex Crichton                     .await?;
54572004aadSNick Fitzgerald                 let idx = module.table_index(table);
546aef5eeb5SAlex Crichton                 let id = store.id();
5479f81f226SAlex Crichton                 let table = store
5489f81f226SAlex Crichton                     .instance_mut(context.instance)
549aef5eeb5SAlex Crichton                     .get_exported_table(id, idx);
550aef5eeb5SAlex Crichton                 let size = table._size(&store);
551aef5eeb5SAlex Crichton                 table._fill(&mut store, 0, init.ref_().unwrap(), size)?;
55272004aadSNick Fitzgerald             }
55372004aadSNick Fitzgerald         }
55472004aadSNick Fitzgerald     }
55572004aadSNick Fitzgerald 
55672004aadSNick Fitzgerald     // Note: if the module's table initializer state is in
55772004aadSNick Fitzgerald     // FuncTable mode, we will lazily initialize tables based on
55872004aadSNick Fitzgerald     // any statically-precomputed image of FuncIndexes, but there
55972004aadSNick Fitzgerald     // may still be "leftover segments" that could not be
56072004aadSNick Fitzgerald     // incorporated. So we have a unified handler here that
56172004aadSNick Fitzgerald     // iterates over all segments (Segments mode) or leftover
56272004aadSNick Fitzgerald     // segments (FuncTable mode) to initialize.
56372004aadSNick Fitzgerald     for segment in module.table_initialization.segments.iter() {
564d1397130SAlex Crichton         let start = const_evaluator
565d1397130SAlex Crichton             .eval_int(&mut store, context, &segment.offset)
566d1397130SAlex Crichton             .expect("const expression should be valid");
5679c3ed199SAlex Crichton         let start = get_index(start, module.tables[segment.table_index].idx_type);
568aad93a48SAlex Crichton         Instance::table_init_segment(
569aef5eeb5SAlex Crichton             &mut store,
570155ea7fcSAlex Crichton             limiter.as_deref_mut(),
571cc8d04f4SAlex Crichton             context.asyncness,
572aad93a48SAlex Crichton             context.instance,
573818966f3SNick Fitzgerald             const_evaluator,
57472004aadSNick Fitzgerald             segment.table_index,
57572004aadSNick Fitzgerald             &segment.elements,
576aef5eeb5SAlex Crichton             start,
57772004aadSNick Fitzgerald             0,
57872004aadSNick Fitzgerald             segment.elements.len(),
579d1397130SAlex Crichton         )
580d1397130SAlex Crichton         .await?;
58172004aadSNick Fitzgerald     }
58272004aadSNick Fitzgerald 
58372004aadSNick Fitzgerald     Ok(())
58472004aadSNick Fitzgerald }
58572004aadSNick Fitzgerald 
get_index(val: &Val, ty: wasmtime_environ::IndexType) -> u64586aef5eeb5SAlex Crichton fn get_index(val: &Val, ty: wasmtime_environ::IndexType) -> u64 {
587aef5eeb5SAlex Crichton     match ty {
588aef5eeb5SAlex Crichton         wasmtime_environ::IndexType::I32 => val.unwrap_i32().cast_unsigned().into(),
589aef5eeb5SAlex Crichton         wasmtime_environ::IndexType::I64 => val.unwrap_i64().cast_unsigned(),
590aef5eeb5SAlex Crichton     }
591aef5eeb5SAlex Crichton }
592aef5eeb5SAlex Crichton 
get_memory_init_start( store: &mut StoreOpaque, init: &MemoryInitializer, instance: InstanceId, context: &mut ConstEvalContext, const_evaluator: &mut ConstExprEvaluator, ) -> Result<u64>5938818b251SNick Fitzgerald fn get_memory_init_start(
5948818b251SNick Fitzgerald     store: &mut StoreOpaque,
5958818b251SNick Fitzgerald     init: &MemoryInitializer,
596aad93a48SAlex Crichton     instance: InstanceId,
597cc8d04f4SAlex Crichton     context: &mut ConstEvalContext,
598cc8d04f4SAlex Crichton     const_evaluator: &mut ConstExprEvaluator,
5998818b251SNick Fitzgerald ) -> Result<u64> {
600aef5eeb5SAlex Crichton     let mut store = OpaqueRootScope::new(store);
601d1397130SAlex Crichton     const_evaluator
602cc8d04f4SAlex Crichton         .eval_int(&mut store, context, &init.offset)
603d1397130SAlex Crichton         .map(|v| {
604aef5eeb5SAlex Crichton             get_index(
605aef5eeb5SAlex Crichton                 v,
606aef5eeb5SAlex Crichton                 store.instance(instance).env_module().memories[init.memory_index].idx_type,
607aef5eeb5SAlex Crichton             )
608b44c23d1SJamey Sharp         })
60972004aadSNick Fitzgerald }
61072004aadSNick Fitzgerald 
check_memory_init_bounds( store: &mut StoreOpaque, instance: InstanceId, initializers: &[MemoryInitializer], context: &mut ConstEvalContext, const_evaluator: &mut ConstExprEvaluator, ) -> Result<()>61172004aadSNick Fitzgerald fn check_memory_init_bounds(
6128818b251SNick Fitzgerald     store: &mut StoreOpaque,
613aad93a48SAlex Crichton     instance: InstanceId,
61472004aadSNick Fitzgerald     initializers: &[MemoryInitializer],
615cc8d04f4SAlex Crichton     context: &mut ConstEvalContext,
616cc8d04f4SAlex Crichton     const_evaluator: &mut ConstExprEvaluator,
61772004aadSNick Fitzgerald ) -> Result<()> {
61872004aadSNick Fitzgerald     for init in initializers {
619aad93a48SAlex Crichton         let memory = store.instance_mut(instance).get_memory(init.memory_index);
620cc8d04f4SAlex Crichton         let start = get_memory_init_start(store, init, instance, context, const_evaluator)?;
62172004aadSNick Fitzgerald         let end = usize::try_from(start)
62272004aadSNick Fitzgerald             .ok()
62372004aadSNick Fitzgerald             .and_then(|start| start.checked_add(init.data.len()));
62472004aadSNick Fitzgerald 
62572004aadSNick Fitzgerald         match end {
62672004aadSNick Fitzgerald             Some(end) if end <= memory.current_length() => {
62772004aadSNick Fitzgerald                 // Initializer is in bounds
62872004aadSNick Fitzgerald             }
62972004aadSNick Fitzgerald             _ => {
630*517c0287SAlex Crichton                 bail!(Trap::MemoryOutOfBounds);
63172004aadSNick Fitzgerald             }
63272004aadSNick Fitzgerald         }
63372004aadSNick Fitzgerald     }
63472004aadSNick Fitzgerald 
63572004aadSNick Fitzgerald     Ok(())
63672004aadSNick Fitzgerald }
63772004aadSNick Fitzgerald 
initialize_memories( store: &mut StoreOpaque, context: &mut ConstEvalContext, const_evaluator: &mut ConstExprEvaluator, module: &Module, ) -> Result<()>638818966f3SNick Fitzgerald fn initialize_memories(
6398818b251SNick Fitzgerald     store: &mut StoreOpaque,
640aad93a48SAlex Crichton     context: &mut ConstEvalContext,
641818966f3SNick Fitzgerald     const_evaluator: &mut ConstExprEvaluator,
642818966f3SNick Fitzgerald     module: &Module,
643818966f3SNick Fitzgerald ) -> Result<()> {
64472004aadSNick Fitzgerald     // Delegates to the `init_memory` method which is sort of a duplicate of
64572004aadSNick Fitzgerald     // `instance.memory_init_segment` but is used at compile-time in other
64672004aadSNick Fitzgerald     // contexts so is shared here to have only one method of memory
64772004aadSNick Fitzgerald     // initialization.
64872004aadSNick Fitzgerald     //
64972004aadSNick Fitzgerald     // This call to `init_memory` notably implements all the bells and whistles
65072004aadSNick Fitzgerald     // so errors only happen if an out-of-bounds segment is found, in which case
65172004aadSNick Fitzgerald     // a trap is returned.
652b44c23d1SJamey Sharp 
653aad93a48SAlex Crichton     struct InitMemoryAtInstantiation<'a> {
654b44c23d1SJamey Sharp         module: &'a Module,
6558818b251SNick Fitzgerald         store: &'a mut StoreOpaque,
656aad93a48SAlex Crichton         context: &'a mut ConstEvalContext,
657818966f3SNick Fitzgerald         const_evaluator: &'a mut ConstExprEvaluator,
658b44c23d1SJamey Sharp     }
659b44c23d1SJamey Sharp 
660aad93a48SAlex Crichton     impl InitMemory for InitMemoryAtInstantiation<'_> {
661bdd78422SNick Fitzgerald         fn memory_size_in_bytes(
662bdd78422SNick Fitzgerald             &mut self,
663bdd78422SNick Fitzgerald             memory: wasmtime_environ::MemoryIndex,
664bdd78422SNick Fitzgerald         ) -> Result<u64, SizeOverflow> {
665aad93a48SAlex Crichton             let len = self
666aad93a48SAlex Crichton                 .store
667aad93a48SAlex Crichton                 .instance(self.context.instance)
668aad93a48SAlex Crichton                 .get_memory(memory)
669aad93a48SAlex Crichton                 .current_length();
670bdd78422SNick Fitzgerald             let len = u64::try_from(len).unwrap();
671bdd78422SNick Fitzgerald             Ok(len)
672b44c23d1SJamey Sharp         }
673b44c23d1SJamey Sharp 
674b44c23d1SJamey Sharp         fn eval_offset(
675b44c23d1SJamey Sharp             &mut self,
676b44c23d1SJamey Sharp             memory: wasmtime_environ::MemoryIndex,
677b44c23d1SJamey Sharp             expr: &wasmtime_environ::ConstExpr,
678b44c23d1SJamey Sharp         ) -> Option<u64> {
679aef5eeb5SAlex Crichton             let mut store = OpaqueRootScope::new(&mut *self.store);
680d1397130SAlex Crichton             let val = self
681d1397130SAlex Crichton                 .const_evaluator
682d1397130SAlex Crichton                 .eval_int(&mut store, self.context, expr)
683b44c23d1SJamey Sharp                 .expect("const expression should be valid");
684aef5eeb5SAlex Crichton             Some(get_index(
685aef5eeb5SAlex Crichton                 val,
686aef5eeb5SAlex Crichton                 store.instance(self.context.instance).env_module().memories[memory].idx_type,
687aef5eeb5SAlex Crichton             ))
688b44c23d1SJamey Sharp         }
689b44c23d1SJamey Sharp 
690b44c23d1SJamey Sharp         fn write(
691b44c23d1SJamey Sharp             &mut self,
692b44c23d1SJamey Sharp             memory_index: wasmtime_environ::MemoryIndex,
693b44c23d1SJamey Sharp             init: &wasmtime_environ::StaticMemoryInitializer,
694b44c23d1SJamey Sharp         ) -> bool {
69572004aadSNick Fitzgerald             // If this initializer applies to a defined memory but that memory
69672004aadSNick Fitzgerald             // doesn't need initialization, due to something like copy-on-write
69772004aadSNick Fitzgerald             // pre-initializing it via mmap magic, then this initializer can be
69872004aadSNick Fitzgerald             // skipped entirely.
699aad93a48SAlex Crichton             let instance = self.store.instance_mut(self.context.instance);
700b44c23d1SJamey Sharp             if let Some(memory_index) = self.module.defined_memory_index(memory_index) {
701aad93a48SAlex Crichton                 if !instance.memories[memory_index].1.needs_init() {
70272004aadSNick Fitzgerald                     return true;
70372004aadSNick Fitzgerald                 }
70472004aadSNick Fitzgerald             }
705aad93a48SAlex Crichton             let memory = instance.get_memory(memory_index);
70672004aadSNick Fitzgerald 
70772004aadSNick Fitzgerald             unsafe {
708aad93a48SAlex Crichton                 let src = instance.wasm_data(init.data.clone());
709c2717d18SAlex Crichton                 let offset = usize::try_from(init.offset).unwrap();
710b86b9682SAlex Crichton                 let dst = memory.base.as_ptr().add(offset);
711c2717d18SAlex Crichton 
712c2717d18SAlex Crichton                 assert!(offset + src.len() <= memory.current_length());
713c2717d18SAlex Crichton 
71472004aadSNick Fitzgerald                 // FIXME audit whether this is safe in the presence of shared
71572004aadSNick Fitzgerald                 // memory
71672004aadSNick Fitzgerald                 // (https://github.com/bytecodealliance/wasmtime/issues/4203).
71772004aadSNick Fitzgerald                 ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len())
71872004aadSNick Fitzgerald             }
71972004aadSNick Fitzgerald             true
720b44c23d1SJamey Sharp         }
721b44c23d1SJamey Sharp     }
722b44c23d1SJamey Sharp 
723b44c23d1SJamey Sharp     let ok = module
724b44c23d1SJamey Sharp         .memory_initialization
725b44c23d1SJamey Sharp         .init_memory(&mut InitMemoryAtInstantiation {
726b44c23d1SJamey Sharp             module,
7278818b251SNick Fitzgerald             store,
728818966f3SNick Fitzgerald             context,
729818966f3SNick Fitzgerald             const_evaluator,
730b44c23d1SJamey Sharp         });
73172004aadSNick Fitzgerald     if !ok {
7329034e101SAlex Crichton         return Err(Trap::MemoryOutOfBounds.into());
73372004aadSNick Fitzgerald     }
73472004aadSNick Fitzgerald 
73572004aadSNick Fitzgerald     Ok(())
73672004aadSNick Fitzgerald }
73772004aadSNick Fitzgerald 
check_init_bounds( store: &mut StoreOpaque, instance: InstanceId, context: &mut ConstEvalContext, const_evaluator: &mut ConstExprEvaluator, module: &Module, ) -> Result<()>738cc8d04f4SAlex Crichton fn check_init_bounds(
739cc8d04f4SAlex Crichton     store: &mut StoreOpaque,
740cc8d04f4SAlex Crichton     instance: InstanceId,
741cc8d04f4SAlex Crichton     context: &mut ConstEvalContext,
742cc8d04f4SAlex Crichton     const_evaluator: &mut ConstExprEvaluator,
743cc8d04f4SAlex Crichton     module: &Module,
744cc8d04f4SAlex Crichton ) -> Result<()> {
745cc8d04f4SAlex Crichton     check_table_init_bounds(store, instance, module, context, const_evaluator)?;
74672004aadSNick Fitzgerald 
74772004aadSNick Fitzgerald     match &module.memory_initialization {
74872004aadSNick Fitzgerald         MemoryInitialization::Segmented(initializers) => {
749cc8d04f4SAlex Crichton             check_memory_init_bounds(store, instance, initializers, context, const_evaluator)?;
75072004aadSNick Fitzgerald         }
75172004aadSNick Fitzgerald         // Statically validated already to have everything in-bounds.
75272004aadSNick Fitzgerald         MemoryInitialization::Static { .. } => {}
75372004aadSNick Fitzgerald     }
75472004aadSNick Fitzgerald 
75572004aadSNick Fitzgerald     Ok(())
75672004aadSNick Fitzgerald }
75772004aadSNick Fitzgerald 
initialize_globals( store: &mut StoreOpaque, mut limiter: Option<&mut StoreResourceLimiter<'_>>, context: &mut ConstEvalContext, const_evaluator: &mut ConstExprEvaluator, module: &Module, ) -> Result<()>758d1397130SAlex Crichton async fn initialize_globals(
7598818b251SNick Fitzgerald     store: &mut StoreOpaque,
760155ea7fcSAlex Crichton     mut limiter: Option<&mut StoreResourceLimiter<'_>>,
761aad93a48SAlex Crichton     context: &mut ConstEvalContext,
762818966f3SNick Fitzgerald     const_evaluator: &mut ConstExprEvaluator,
763818966f3SNick Fitzgerald     module: &Module,
764818966f3SNick Fitzgerald ) -> Result<()> {
765aad93a48SAlex Crichton     assert!(core::ptr::eq(
766aad93a48SAlex Crichton         &**store.instance(context.instance).env_module(),
767aad93a48SAlex Crichton         module
768aad93a48SAlex Crichton     ));
769818966f3SNick Fitzgerald 
770aef5eeb5SAlex Crichton     let mut store = OpaqueRootScope::new(store);
7718818b251SNick Fitzgerald 
772818966f3SNick Fitzgerald     for (index, init) in module.global_initializers.iter() {
773d1397130SAlex Crichton         // Attempt a simple, synchronous evaluation before hitting the
774d1397130SAlex Crichton         // general-purpose `.await` point below. This benchmarks ~15% faster in
775d1397130SAlex Crichton         // instantiation vs just falling through to `.await` below.
776d1397130SAlex Crichton         let val = if let Some(val) = const_evaluator.try_simple(init) {
777d1397130SAlex Crichton             val
778d1397130SAlex Crichton         } else {
779818966f3SNick Fitzgerald             const_evaluator
780155ea7fcSAlex Crichton                 .eval(&mut store, limiter.as_deref_mut(), context, init)
78179419198SAlex Crichton                 .await?
782818966f3SNick Fitzgerald         };
783818966f3SNick Fitzgerald 
784aef5eeb5SAlex Crichton         let id = store.id();
785aef5eeb5SAlex Crichton         let index = module.global_index(index);
786aef5eeb5SAlex Crichton         let mut instance = store.instance_mut(context.instance);
787818966f3SNick Fitzgerald 
788818966f3SNick Fitzgerald         #[cfg(feature = "wmemcheck")]
789aef5eeb5SAlex Crichton         if index.as_u32() == 0
790aef5eeb5SAlex Crichton             && module.globals[index].wasm_ty == wasmtime_environ::WasmValType::I32
791aef5eeb5SAlex Crichton         {
792aef5eeb5SAlex Crichton             if let Some(wmemcheck) = instance.as_mut().wmemcheck_state_mut() {
793aef5eeb5SAlex Crichton                 let size = usize::try_from(val.unwrap_i32()).unwrap();
794818966f3SNick Fitzgerald                 wmemcheck.set_stack_size(size);
795818966f3SNick Fitzgerald             }
796818966f3SNick Fitzgerald         }
797818966f3SNick Fitzgerald 
798aef5eeb5SAlex Crichton         let global = instance.as_mut().get_exported_global(id, index);
799aef5eeb5SAlex Crichton 
800aef5eeb5SAlex Crichton         // Note that mutability is bypassed here because this is, by definition,
801aef5eeb5SAlex Crichton         // initialization of globals meaning that if it's an immutable global
802aef5eeb5SAlex Crichton         // this is the one and only write.
803aef5eeb5SAlex Crichton         //
804aef5eeb5SAlex Crichton         // SAFETY: this is a valid module so `val` should have the correct type
805aef5eeb5SAlex Crichton         // for this global, and it's safe to write to a global for the first
806aef5eeb5SAlex Crichton         // time as-is happening here.
807818966f3SNick Fitzgerald         unsafe {
808aef5eeb5SAlex Crichton             global.set_unchecked(&mut store, &val)?;
809aef5eeb5SAlex Crichton         }
810818966f3SNick Fitzgerald     }
811818966f3SNick Fitzgerald     Ok(())
812818966f3SNick Fitzgerald }
813818966f3SNick Fitzgerald 
initialize_instance( store: &mut StoreOpaque, mut limiter: Option<&mut StoreResourceLimiter<'_>>, instance: InstanceId, module: &Module, is_bulk_memory: bool, asyncness: Asyncness, ) -> Result<()>814d1397130SAlex Crichton pub async fn initialize_instance(
8158818b251SNick Fitzgerald     store: &mut StoreOpaque,
816155ea7fcSAlex Crichton     mut limiter: Option<&mut StoreResourceLimiter<'_>>,
817aad93a48SAlex Crichton     instance: InstanceId,
81872004aadSNick Fitzgerald     module: &Module,
81972004aadSNick Fitzgerald     is_bulk_memory: bool,
820cc8d04f4SAlex Crichton     asyncness: Asyncness,
82172004aadSNick Fitzgerald ) -> Result<()> {
822cc8d04f4SAlex Crichton     let mut context = ConstEvalContext::new(instance, asyncness);
823cc8d04f4SAlex Crichton     let mut const_evaluator = ConstExprEvaluator::default();
824cc8d04f4SAlex Crichton 
82572004aadSNick Fitzgerald     // If bulk memory is not enabled, bounds check the data and element segments before
82672004aadSNick Fitzgerald     // making any changes. With bulk memory enabled, initializers are processed
82772004aadSNick Fitzgerald     // in-order and side effects are observed up to the point of an out-of-bounds
82872004aadSNick Fitzgerald     // initializer, so the early checking is not desired.
82972004aadSNick Fitzgerald     if !is_bulk_memory {
830cc8d04f4SAlex Crichton         check_init_bounds(store, instance, &mut context, &mut const_evaluator, module)?;
83172004aadSNick Fitzgerald     }
83272004aadSNick Fitzgerald 
833155ea7fcSAlex Crichton     initialize_globals(
834155ea7fcSAlex Crichton         store,
835155ea7fcSAlex Crichton         limiter.as_deref_mut(),
836155ea7fcSAlex Crichton         &mut context,
837155ea7fcSAlex Crichton         &mut const_evaluator,
838155ea7fcSAlex Crichton         module,
839155ea7fcSAlex Crichton     )
840155ea7fcSAlex Crichton     .await?;
841155ea7fcSAlex Crichton     initialize_tables(
842155ea7fcSAlex Crichton         store,
843155ea7fcSAlex Crichton         limiter.as_deref_mut(),
844155ea7fcSAlex Crichton         &mut context,
845155ea7fcSAlex Crichton         &mut const_evaluator,
846155ea7fcSAlex Crichton         module,
847155ea7fcSAlex Crichton     )
848155ea7fcSAlex Crichton     .await?;
8498818b251SNick Fitzgerald     initialize_memories(store, &mut context, &mut const_evaluator, &module)?;
85072004aadSNick Fitzgerald 
85172004aadSNick Fitzgerald     Ok(())
85272004aadSNick Fitzgerald }
85372004aadSNick Fitzgerald 
85472004aadSNick Fitzgerald #[cfg(test)]
85572004aadSNick Fitzgerald mod tests {
85672004aadSNick Fitzgerald     use super::*;
85772004aadSNick Fitzgerald 
85872004aadSNick Fitzgerald     #[test]
allocator_traits_are_object_safe()85972004aadSNick Fitzgerald     fn allocator_traits_are_object_safe() {
860f8177c20SAlex Crichton         fn _instance_allocator(_: &dyn InstanceAllocator) {}
86172004aadSNick Fitzgerald     }
86272004aadSNick Fitzgerald }
863