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