1 use crate::prelude::*;
2 use crate::runtime::vm::const_expr::{ConstEvalContext, ConstExprEvaluator};
3 use crate::runtime::vm::imports::Imports;
4 use crate::runtime::vm::instance::{Instance, InstanceHandle};
5 use crate::runtime::vm::memory::Memory;
6 use crate::runtime::vm::mpk::ProtectionKey;
7 use crate::runtime::vm::table::Table;
8 use crate::runtime::vm::{CompiledModuleId, ModuleRuntimeInfo, VMFuncRef, VMGcRef, VMStore};
9 use crate::store::{AutoAssertNoGc, InstanceId, StoreOpaque};
10 use crate::vm::VMGlobalDefinition;
11 use core::ptr::NonNull;
12 use core::{mem, ptr};
13 use wasmtime_environ::{
14     DefinedMemoryIndex, DefinedTableIndex, HostPtr, InitMemory, MemoryInitialization,
15     MemoryInitializer, Module, PrimaryMap, SizeOverflow, TableInitialValue, Trap, Tunables,
16     VMOffsets, WasmHeapTopType,
17 };
18 
19 #[cfg(feature = "gc")]
20 use crate::runtime::vm::{GcHeap, GcRuntime};
21 
22 #[cfg(feature = "component-model")]
23 use wasmtime_environ::{
24     StaticModuleIndex,
25     component::{Component, VMComponentOffsets},
26 };
27 
28 mod on_demand;
29 pub use self::on_demand::OnDemandInstanceAllocator;
30 
31 #[cfg(feature = "pooling-allocator")]
32 mod pooling;
33 #[cfg(feature = "pooling-allocator")]
34 pub use self::pooling::{
35     InstanceLimits, PoolConcurrencyLimitError, PoolingInstanceAllocator,
36     PoolingInstanceAllocatorConfig,
37 };
38 
39 /// Represents a request for a new runtime instance.
40 pub struct InstanceAllocationRequest<'a> {
41     /// The instance id that this will be assigned within the store once the
42     /// allocation has finished.
43     pub id: InstanceId,
44 
45     /// The info related to the compiled version of this module,
46     /// needed for instantiation: function metadata, JIT code
47     /// addresses, precomputed images for lazy memory and table
48     /// initialization, and the like. This Arc is cloned and held for
49     /// the lifetime of the instance.
50     pub runtime_info: &'a ModuleRuntimeInfo,
51 
52     /// The imports to use for the instantiation.
53     pub imports: Imports<'a>,
54 
55     /// A pointer to the "store" for this instance to be allocated. The store
56     /// correlates with the `Store` in wasmtime itself, and lots of contextual
57     /// information about the execution of wasm can be learned through the
58     /// store.
59     ///
60     /// Note that this is a raw pointer and has a static lifetime, both of which
61     /// are a bit of a lie. This is done purely so a store can learn about
62     /// itself when it gets called as a host function, and additionally so this
63     /// runtime can access internals as necessary (such as the
64     /// VMExternRefActivationsTable or the resource limiter methods).
65     ///
66     /// Note that this ends up being a self-pointer to the instance when stored.
67     /// The reason is that the instance itself is then stored within the store.
68     /// We use a number of `PhantomPinned` declarations to indicate this to the
69     /// compiler. More info on this in `wasmtime/src/store.rs`
70     pub store: StorePtr,
71 
72     /// Indicates '--wmemcheck' flag.
73     #[cfg(feature = "wmemcheck")]
74     pub wmemcheck: bool,
75 
76     /// Request that the instance's memories be protected by a specific
77     /// protection key.
78     #[cfg_attr(
79         not(feature = "pooling-allocator"),
80         expect(
81             dead_code,
82             reason = "easier to keep this field than remove it, not perf-critical to remove"
83         )
84     )]
85     pub pkey: Option<ProtectionKey>,
86 
87     /// Tunable configuration options the engine is using.
88     pub tunables: &'a Tunables,
89 }
90 
91 /// A pointer to a Store. This Option<*mut dyn Store> is wrapped in a struct
92 /// so that the function to create a &mut dyn Store is a method on a member of
93 /// InstanceAllocationRequest, rather than on a &mut InstanceAllocationRequest
94 /// itself, because several use-sites require a split mut borrow on the
95 /// InstanceAllocationRequest.
96 pub struct StorePtr(Option<NonNull<dyn VMStore>>);
97 
98 // We can't make `VMStore: Send + Sync` because that requires making all of
99 // Wastime's internals generic over the `Store`'s `T`. So instead, we take care
100 // in the whole VM layer to only use the `VMStore` in ways that are `Send`- and
101 // `Sync`-safe and we have to have these unsafe impls.
102 unsafe impl Send for StorePtr {}
103 unsafe impl Sync for StorePtr {}
104 
105 impl StorePtr {
106     /// A pointer to no Store.
107     pub fn empty() -> Self {
108         Self(None)
109     }
110 
111     /// A pointer to a Store.
112     pub fn new(ptr: NonNull<dyn VMStore>) -> Self {
113         Self(Some(ptr))
114     }
115 
116     /// The raw contents of this struct
117     pub fn as_raw(&self) -> Option<NonNull<dyn VMStore>> {
118         self.0
119     }
120 
121     /// Use the StorePtr as a mut ref to the Store.
122     ///
123     /// Safety: must not be used outside the original lifetime of the borrow.
124     pub(crate) unsafe fn get(&mut self) -> Option<&mut dyn VMStore> {
125         let ptr = unsafe { self.0?.as_mut() };
126         Some(ptr)
127     }
128 }
129 
130 /// The index of a memory allocation within an `InstanceAllocator`.
131 #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
132 pub struct MemoryAllocationIndex(u32);
133 
134 impl Default for MemoryAllocationIndex {
135     fn default() -> Self {
136         // A default `MemoryAllocationIndex` that can be used with
137         // `InstanceAllocator`s that don't actually need indices.
138         MemoryAllocationIndex(u32::MAX)
139     }
140 }
141 
142 impl MemoryAllocationIndex {
143     /// Get the underlying index of this `MemoryAllocationIndex`.
144     #[cfg(feature = "pooling-allocator")]
145     pub fn index(&self) -> usize {
146         self.0 as usize
147     }
148 }
149 
150 /// The index of a table allocation within an `InstanceAllocator`.
151 #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
152 pub struct TableAllocationIndex(u32);
153 
154 impl Default for TableAllocationIndex {
155     fn default() -> Self {
156         // A default `TableAllocationIndex` that can be used with
157         // `InstanceAllocator`s that don't actually need indices.
158         TableAllocationIndex(u32::MAX)
159     }
160 }
161 
162 impl TableAllocationIndex {
163     /// Get the underlying index of this `TableAllocationIndex`.
164     #[cfg(feature = "pooling-allocator")]
165     pub fn index(&self) -> usize {
166         self.0 as usize
167     }
168 }
169 
170 /// The index of a table allocation within an `InstanceAllocator`.
171 #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
172 pub struct GcHeapAllocationIndex(u32);
173 
174 impl Default for GcHeapAllocationIndex {
175     fn default() -> Self {
176         // A default `GcHeapAllocationIndex` that can be used with
177         // `InstanceAllocator`s that don't actually need indices.
178         GcHeapAllocationIndex(u32::MAX)
179     }
180 }
181 
182 impl GcHeapAllocationIndex {
183     /// Get the underlying index of this `GcHeapAllocationIndex`.
184     pub fn index(&self) -> usize {
185         self.0 as usize
186     }
187 }
188 
189 /// Trait that represents the hooks needed to implement an instance allocator.
190 ///
191 /// Implement this trait when implementing new instance allocators, but don't
192 /// use this trait when you need an instance allocator. Instead use the
193 /// `InstanceAllocator` trait for that, which has additional helper methods and
194 /// a blanket implementation for all types that implement this trait.
195 ///
196 /// # Safety
197 ///
198 /// This trait is unsafe as it requires knowledge of Wasmtime's runtime
199 /// internals to implement correctly.
200 pub unsafe trait InstanceAllocatorImpl {
201     /// Validate whether a component (including all of its contained core
202     /// modules) is allocatable by this instance allocator.
203     #[cfg(feature = "component-model")]
204     fn validate_component_impl<'a>(
205         &self,
206         component: &Component,
207         offsets: &VMComponentOffsets<HostPtr>,
208         get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module,
209     ) -> Result<()>;
210 
211     /// Validate whether a module is allocatable by this instance allocator.
212     fn validate_module_impl(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()>;
213 
214     /// Validate whether a memory is allocatable by this instance allocator.
215     #[cfg(feature = "gc")]
216     fn validate_memory_impl(&self, memory: &wasmtime_environ::Memory) -> Result<()>;
217 
218     /// Increment the count of concurrent component instances that are currently
219     /// allocated, if applicable.
220     ///
221     /// Not all instance allocators will have limits for the maximum number of
222     /// concurrent component instances that can be live at the same time, and
223     /// these allocators may implement this method with a no-op.
224     //
225     // Note: It would be nice to have an associated type that on construction
226     // does the increment and on drop does the decrement but there are two
227     // problems with this:
228     //
229     // 1. This trait's implementations are always used as trait objects, and
230     //    associated types are not object safe.
231     //
232     // 2. We would want a parameterized `Drop` implementation so that we could
233     //    pass in the `InstanceAllocatorImpl` on drop, but this doesn't exist in
234     //    Rust. Therefore, we would be forced to add reference counting and
235     //    stuff like that to keep a handle on the instance allocator from this
236     //    theoretical type. That's a bummer.
237     #[cfg(feature = "component-model")]
238     fn increment_component_instance_count(&self) -> Result<()>;
239 
240     /// The dual of `increment_component_instance_count`.
241     #[cfg(feature = "component-model")]
242     fn decrement_component_instance_count(&self);
243 
244     /// Increment the count of concurrent core module instances that are
245     /// currently allocated, if applicable.
246     ///
247     /// Not all instance allocators will have limits for the maximum number of
248     /// concurrent core module instances that can be live at the same time, and
249     /// these allocators may implement this method with a no-op.
250     fn increment_core_instance_count(&self) -> Result<()>;
251 
252     /// The dual of `increment_core_instance_count`.
253     fn decrement_core_instance_count(&self);
254 
255     /// Allocate a memory for an instance.
256     ///
257     /// # Unsafety
258     ///
259     /// The memory and its associated module must have already been validated by
260     /// `Self::validate_memory` (or transtively via
261     /// `Self::validate_{module,component}`) and passed that validation.
262     unsafe fn allocate_memory(
263         &self,
264         request: &mut InstanceAllocationRequest,
265         ty: &wasmtime_environ::Memory,
266         tunables: &Tunables,
267         memory_index: Option<DefinedMemoryIndex>,
268     ) -> Result<(MemoryAllocationIndex, Memory)>;
269 
270     /// Deallocate an instance's previously allocated memory.
271     ///
272     /// # Unsafety
273     ///
274     /// The memory must have previously been allocated by
275     /// `Self::allocate_memory`, be at the given index, and must currently be
276     /// allocated. It must never be used again.
277     unsafe fn deallocate_memory(
278         &self,
279         memory_index: Option<DefinedMemoryIndex>,
280         allocation_index: MemoryAllocationIndex,
281         memory: Memory,
282     );
283 
284     /// Allocate a table for an instance.
285     ///
286     /// # Unsafety
287     ///
288     /// The table and its associated module must have already been validated by
289     /// `Self::validate_module` and passed that validation.
290     unsafe fn allocate_table(
291         &self,
292         req: &mut InstanceAllocationRequest,
293         table: &wasmtime_environ::Table,
294         tunables: &Tunables,
295         table_index: DefinedTableIndex,
296     ) -> Result<(TableAllocationIndex, Table)>;
297 
298     /// Deallocate an instance's previously allocated table.
299     ///
300     /// # Unsafety
301     ///
302     /// The table must have previously been allocated by `Self::allocate_table`,
303     /// be at the given index, and must currently be allocated. It must never be
304     /// used again.
305     unsafe fn deallocate_table(
306         &self,
307         table_index: DefinedTableIndex,
308         allocation_index: TableAllocationIndex,
309         table: Table,
310     );
311 
312     /// Allocates a fiber stack for calling async functions on.
313     #[cfg(feature = "async")]
314     fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack>;
315 
316     /// Deallocates a fiber stack that was previously allocated with
317     /// `allocate_fiber_stack`.
318     ///
319     /// # Safety
320     ///
321     /// The provided stack is required to have been allocated with
322     /// `allocate_fiber_stack`.
323     #[cfg(feature = "async")]
324     unsafe fn deallocate_fiber_stack(&self, stack: wasmtime_fiber::FiberStack);
325 
326     /// Allocate a GC heap for allocating Wasm GC objects within.
327     #[cfg(feature = "gc")]
328     fn allocate_gc_heap(
329         &self,
330         engine: &crate::Engine,
331         gc_runtime: &dyn GcRuntime,
332         memory_alloc_index: MemoryAllocationIndex,
333         memory: Memory,
334     ) -> Result<(GcHeapAllocationIndex, Box<dyn GcHeap>)>;
335 
336     /// Deallocate a GC heap that was previously allocated with
337     /// `allocate_gc_heap`.
338     #[cfg(feature = "gc")]
339     #[must_use = "it is the caller's responsibility to deallocate the GC heap's underlying memory \
340                   storage after the GC heap is deallocated"]
341     fn deallocate_gc_heap(
342         &self,
343         allocation_index: GcHeapAllocationIndex,
344         gc_heap: Box<dyn GcHeap>,
345     ) -> (MemoryAllocationIndex, Memory);
346 
347     /// Purges all lingering resources related to `module` from within this
348     /// allocator.
349     ///
350     /// Primarily present for the pooling allocator to remove mappings of
351     /// this module from slots in linear memory.
352     fn purge_module(&self, module: CompiledModuleId);
353 
354     /// Use the next available protection key.
355     ///
356     /// The pooling allocator can use memory protection keys (MPK) for
357     /// compressing the guard regions protecting against OOB. Each
358     /// pool-allocated store needs its own key.
359     fn next_available_pkey(&self) -> Option<ProtectionKey>;
360 
361     /// Restrict access to memory regions protected by `pkey`.
362     ///
363     /// This is useful for the pooling allocator, which can use memory
364     /// protection keys (MPK). Note: this may still allow access to other
365     /// protection keys, such as the default kernel key; see implementations of
366     /// this.
367     fn restrict_to_pkey(&self, pkey: ProtectionKey);
368 
369     /// Allow access to memory regions protected by any protection key.
370     fn allow_all_pkeys(&self);
371 }
372 
373 /// A thing that can allocate instances.
374 ///
375 /// Don't implement this trait directly, instead implement
376 /// `InstanceAllocatorImpl` and you'll get this trait for free via a blanket
377 /// impl.
378 pub trait InstanceAllocator: InstanceAllocatorImpl {
379     /// Validate whether a component (including all of its contained core
380     /// modules) is allocatable with this instance allocator.
381     #[cfg(feature = "component-model")]
382     fn validate_component<'a>(
383         &self,
384         component: &Component,
385         offsets: &VMComponentOffsets<HostPtr>,
386         get_module: &'a dyn Fn(StaticModuleIndex) -> &'a Module,
387     ) -> Result<()> {
388         InstanceAllocatorImpl::validate_component_impl(self, component, offsets, get_module)
389     }
390 
391     /// Validate whether a core module is allocatable with this instance
392     /// allocator.
393     fn validate_module(&self, module: &Module, offsets: &VMOffsets<HostPtr>) -> Result<()> {
394         InstanceAllocatorImpl::validate_module_impl(self, module, offsets)
395     }
396 
397     /// Validate whether a memory is allocatable with this instance allocator.
398     #[cfg(feature = "gc")]
399     fn validate_memory(&self, memory: &wasmtime_environ::Memory) -> Result<()> {
400         InstanceAllocatorImpl::validate_memory_impl(self, memory)
401     }
402 
403     /// Allocates a fresh `InstanceHandle` for the `req` given.
404     ///
405     /// This will allocate memories and tables internally from this allocator
406     /// and weave that altogether into a final and complete `InstanceHandle`
407     /// ready to be registered with a store.
408     ///
409     /// Note that the returned instance must still have `.initialize(..)` called
410     /// on it to complete the instantiation process.
411     ///
412     /// # Unsafety
413     ///
414     /// The request's associated module, memories, tables, and vmctx must have
415     /// already have been validated by `Self::validate_module`.
416     unsafe fn allocate_module(
417         &self,
418         mut request: InstanceAllocationRequest,
419     ) -> Result<InstanceHandle> {
420         let module = request.runtime_info.env_module();
421 
422         #[cfg(debug_assertions)]
423         InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets())
424             .expect("module should have already been validated before allocation");
425 
426         self.increment_core_instance_count()?;
427 
428         let num_defined_memories = module.num_defined_memories();
429         let mut memories = PrimaryMap::with_capacity(num_defined_memories);
430 
431         let num_defined_tables = module.num_defined_tables();
432         let mut tables = PrimaryMap::with_capacity(num_defined_tables);
433 
434         match (|| {
435             // SAFETY: validation of tables/memories is a contract of this
436             // function.
437             unsafe {
438                 self.allocate_memories(&mut request, &mut memories)?;
439                 self.allocate_tables(&mut request, &mut tables)?;
440             }
441             Ok(())
442         })() {
443             Ok(_) => Ok(Instance::new(request, memories, tables, &module.memories)),
444             Err(e) => {
445                 // SAFETY: these were previously allocated by this allocator
446                 unsafe {
447                     self.deallocate_memories(&mut memories);
448                     self.deallocate_tables(&mut tables);
449                 }
450                 self.decrement_core_instance_count();
451                 Err(e)
452             }
453         }
454     }
455 
456     /// Deallocates the provided instance.
457     ///
458     /// This will null-out the pointer within `handle` and otherwise reclaim
459     /// resources such as tables, memories, and the instance memory itself.
460     ///
461     /// # Unsafety
462     ///
463     /// The instance must have previously been allocated by `Self::allocate`.
464     unsafe fn deallocate_module(&self, handle: &mut InstanceHandle) {
465         // SAFETY: the contract of `deallocate_*` is itself a contract of this
466         // function, that the memories/tables were previously allocated from
467         // here.
468         unsafe {
469             self.deallocate_memories(handle.get_mut().memories_mut());
470             self.deallocate_tables(handle.get_mut().tables_mut());
471         }
472 
473         self.decrement_core_instance_count();
474     }
475 
476     /// Allocate the memories for the given instance allocation request, pushing
477     /// them into `memories`.
478     ///
479     /// # Unsafety
480     ///
481     /// The request's associated module and memories must have previously been
482     /// validated by `Self::validate_module`.
483     unsafe fn allocate_memories(
484         &self,
485         request: &mut InstanceAllocationRequest,
486         memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
487     ) -> Result<()> {
488         let module = request.runtime_info.env_module();
489 
490         #[cfg(debug_assertions)]
491         InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets())
492             .expect("module should have already been validated before allocation");
493 
494         for (memory_index, ty) in module.memories.iter().skip(module.num_imported_memories) {
495             let memory_index = module
496                 .defined_memory_index(memory_index)
497                 .expect("should be a defined memory since we skipped imported ones");
498 
499             // SAFETY: validation of the memory from this allocator is itself a
500             // contract of this function.
501             let memory =
502                 unsafe { self.allocate_memory(request, ty, request.tunables, Some(memory_index))? };
503             memories.push(memory);
504         }
505 
506         Ok(())
507     }
508 
509     /// Deallocate all the memories in the given primary map.
510     ///
511     /// # Unsafety
512     ///
513     /// The memories must have previously been allocated by
514     /// `Self::allocate_memories`.
515     unsafe fn deallocate_memories(
516         &self,
517         memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
518     ) {
519         for (memory_index, (allocation_index, memory)) in mem::take(memories) {
520             // Because deallocating memory is infallible, we don't need to worry
521             // about leaking subsequent memories if the first memory failed to
522             // deallocate. If deallocating memory ever becomes fallible, we will
523             // need to be careful here!
524             //
525             // SAFETY: the unsafe contract here is the same as the unsafe
526             // contract of this function, that the memories were previously
527             // allocated by this allocator.
528             unsafe {
529                 self.deallocate_memory(Some(memory_index), allocation_index, memory);
530             }
531         }
532     }
533 
534     /// Allocate tables for the given instance allocation request, pushing them
535     /// into `tables`.
536     ///
537     /// # Unsafety
538     ///
539     /// The request's associated module and tables must have previously been
540     /// validated by `Self::validate_module`.
541     unsafe fn allocate_tables(
542         &self,
543         request: &mut InstanceAllocationRequest,
544         tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
545     ) -> Result<()> {
546         let module = request.runtime_info.env_module();
547 
548         #[cfg(debug_assertions)]
549         InstanceAllocatorImpl::validate_module_impl(self, module, request.runtime_info.offsets())
550             .expect("module should have already been validated before allocation");
551 
552         for (index, table) in module.tables.iter().skip(module.num_imported_tables) {
553             let def_index = module
554                 .defined_table_index(index)
555                 .expect("should be a defined table since we skipped imported ones");
556 
557             // SAFETY: the contract here is that the table has been validated by
558             // this allocator which is a contract of this function itself.
559             let table =
560                 unsafe { self.allocate_table(request, table, request.tunables, def_index)? };
561             tables.push(table);
562         }
563 
564         Ok(())
565     }
566 
567     /// Deallocate all the tables in the given primary map.
568     ///
569     /// # Unsafety
570     ///
571     /// The tables must have previously been allocated by
572     /// `Self::allocate_tables`.
573     unsafe fn deallocate_tables(
574         &self,
575         tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
576     ) {
577         for (table_index, (allocation_index, table)) in mem::take(tables) {
578             // SAFETY: the tables here were allocated from this allocator per
579             // the contract on this function itself.
580             unsafe {
581                 self.deallocate_table(table_index, allocation_index, table);
582             }
583         }
584     }
585 }
586 
587 // Every `InstanceAllocatorImpl` is an `InstanceAllocator` when used
588 // correctly. Also, no one is allowed to override this trait's methods, they
589 // must use the defaults. This blanket impl provides both of those things.
590 impl<T: InstanceAllocatorImpl> InstanceAllocator for T {}
591 
592 fn check_table_init_bounds(
593     store: &mut StoreOpaque,
594     instance: InstanceId,
595     module: &Module,
596 ) -> Result<()> {
597     let mut const_evaluator = ConstExprEvaluator::default();
598 
599     for segment in module.table_initialization.segments.iter() {
600         let mut context = ConstEvalContext::new(instance);
601         let start = unsafe {
602             const_evaluator
603                 .eval(store, &mut context, &segment.offset)
604                 .expect("const expression should be valid")
605         };
606         let start = usize::try_from(start.get_u32()).unwrap();
607         let end = start.checked_add(usize::try_from(segment.elements.len()).unwrap());
608 
609         let table = store.instance_mut(instance).get_table(segment.table_index);
610         match end {
611             Some(end) if end <= table.size() => {
612                 // Initializer is in bounds
613             }
614             _ => {
615                 bail!("table out of bounds: elements segment does not fit")
616             }
617         }
618     }
619 
620     Ok(())
621 }
622 
623 fn initialize_tables(
624     store: &mut StoreOpaque,
625     context: &mut ConstEvalContext,
626     const_evaluator: &mut ConstExprEvaluator,
627     module: &Module,
628 ) -> Result<()> {
629     for (table, init) in module.table_initialization.initial_values.iter() {
630         match init {
631             // Tables are always initially null-initialized at this time
632             TableInitialValue::Null { precomputed: _ } => {}
633 
634             TableInitialValue::Expr(expr) => {
635                 let raw = unsafe {
636                     const_evaluator
637                         .eval(store, context, expr)
638                         .expect("const expression should be valid")
639                 };
640                 let idx = module.table_index(table);
641                 match module.tables[idx].ref_type.heap_type.top() {
642                     WasmHeapTopType::Extern => {
643                         store.gc_store_mut()?;
644                         let (gc_store, instance) =
645                             store.optional_gc_store_and_instance_mut(context.instance);
646                         let gc_store = gc_store.unwrap();
647                         let table = instance.get_defined_table(table);
648                         let gc_ref = VMGcRef::from_raw_u32(raw.get_externref());
649                         let items = (0..table.size())
650                             .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r)));
651                         table.init_gc_refs(0, items)?;
652                     }
653 
654                     WasmHeapTopType::Any => {
655                         store.gc_store_mut()?;
656                         let (gc_store, instance) =
657                             store.optional_gc_store_and_instance_mut(context.instance);
658                         let gc_store = gc_store.unwrap();
659                         let table = instance.get_defined_table(table);
660                         let gc_ref = VMGcRef::from_raw_u32(raw.get_anyref());
661                         let items = (0..table.size())
662                             .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r)));
663                         table.init_gc_refs(0, items)?;
664                     }
665 
666                     WasmHeapTopType::Exn => {
667                         store.gc_store_mut()?;
668                         let (gc_store, instance) =
669                             store.optional_gc_store_and_instance_mut(context.instance);
670                         let gc_store = gc_store.unwrap();
671                         let table = instance.get_defined_table(table);
672                         let gc_ref = VMGcRef::from_raw_u32(raw.get_exnref());
673                         let items = (0..table.size())
674                             .map(|_| gc_ref.as_ref().map(|r| gc_store.clone_gc_ref(r)));
675                         table.init_gc_refs(0, items)?;
676                     }
677 
678                     WasmHeapTopType::Func => {
679                         let table = store
680                             .instance_mut(context.instance)
681                             .get_defined_table(table);
682                         let funcref = NonNull::new(raw.get_funcref().cast::<VMFuncRef>());
683                         let items = (0..table.size()).map(|_| funcref);
684                         table.init_func(0, items)?;
685                     }
686 
687                     WasmHeapTopType::Cont => todo!(), // FIXME: #10248 stack switching support.
688                 }
689             }
690         }
691     }
692 
693     // Note: if the module's table initializer state is in
694     // FuncTable mode, we will lazily initialize tables based on
695     // any statically-precomputed image of FuncIndexes, but there
696     // may still be "leftover segments" that could not be
697     // incorporated. So we have a unified handler here that
698     // iterates over all segments (Segments mode) or leftover
699     // segments (FuncTable mode) to initialize.
700     for segment in module.table_initialization.segments.iter() {
701         let start = unsafe {
702             const_evaluator
703                 .eval(store, context, &segment.offset)
704                 .expect("const expression should be valid")
705         };
706         Instance::table_init_segment(
707             store,
708             context.instance,
709             const_evaluator,
710             segment.table_index,
711             &segment.elements,
712             start.get_u64(),
713             0,
714             segment.elements.len(),
715         )?;
716     }
717 
718     Ok(())
719 }
720 
721 fn get_memory_init_start(
722     store: &mut StoreOpaque,
723     init: &MemoryInitializer,
724     instance: InstanceId,
725 ) -> Result<u64> {
726     let mut context = ConstEvalContext::new(instance);
727     let mut const_evaluator = ConstExprEvaluator::default();
728     unsafe { const_evaluator.eval(store, &mut context, &init.offset) }.map(|v| {
729         match store.instance(instance).env_module().memories[init.memory_index].idx_type {
730             wasmtime_environ::IndexType::I32 => v.get_u32().into(),
731             wasmtime_environ::IndexType::I64 => v.get_u64(),
732         }
733     })
734 }
735 
736 fn check_memory_init_bounds(
737     store: &mut StoreOpaque,
738     instance: InstanceId,
739     initializers: &[MemoryInitializer],
740 ) -> Result<()> {
741     for init in initializers {
742         let memory = store.instance_mut(instance).get_memory(init.memory_index);
743         let start = get_memory_init_start(store, init, instance)?;
744         let end = usize::try_from(start)
745             .ok()
746             .and_then(|start| start.checked_add(init.data.len()));
747 
748         match end {
749             Some(end) if end <= memory.current_length() => {
750                 // Initializer is in bounds
751             }
752             _ => {
753                 bail!("memory out of bounds: data segment does not fit")
754             }
755         }
756     }
757 
758     Ok(())
759 }
760 
761 fn initialize_memories(
762     store: &mut StoreOpaque,
763     context: &mut ConstEvalContext,
764     const_evaluator: &mut ConstExprEvaluator,
765     module: &Module,
766 ) -> Result<()> {
767     // Delegates to the `init_memory` method which is sort of a duplicate of
768     // `instance.memory_init_segment` but is used at compile-time in other
769     // contexts so is shared here to have only one method of memory
770     // initialization.
771     //
772     // This call to `init_memory` notably implements all the bells and whistles
773     // so errors only happen if an out-of-bounds segment is found, in which case
774     // a trap is returned.
775 
776     struct InitMemoryAtInstantiation<'a> {
777         module: &'a Module,
778         store: &'a mut StoreOpaque,
779         context: &'a mut ConstEvalContext,
780         const_evaluator: &'a mut ConstExprEvaluator,
781     }
782 
783     impl InitMemory for InitMemoryAtInstantiation<'_> {
784         fn memory_size_in_bytes(
785             &mut self,
786             memory: wasmtime_environ::MemoryIndex,
787         ) -> Result<u64, SizeOverflow> {
788             let len = self
789                 .store
790                 .instance(self.context.instance)
791                 .get_memory(memory)
792                 .current_length();
793             let len = u64::try_from(len).unwrap();
794             Ok(len)
795         }
796 
797         fn eval_offset(
798             &mut self,
799             memory: wasmtime_environ::MemoryIndex,
800             expr: &wasmtime_environ::ConstExpr,
801         ) -> Option<u64> {
802             let val = unsafe { self.const_evaluator.eval(self.store, self.context, expr) }
803                 .expect("const expression should be valid");
804             Some(
805                 match self
806                     .store
807                     .instance(self.context.instance)
808                     .env_module()
809                     .memories[memory]
810                     .idx_type
811                 {
812                     wasmtime_environ::IndexType::I32 => val.get_u32().into(),
813                     wasmtime_environ::IndexType::I64 => val.get_u64(),
814                 },
815             )
816         }
817 
818         fn write(
819             &mut self,
820             memory_index: wasmtime_environ::MemoryIndex,
821             init: &wasmtime_environ::StaticMemoryInitializer,
822         ) -> bool {
823             // If this initializer applies to a defined memory but that memory
824             // doesn't need initialization, due to something like copy-on-write
825             // pre-initializing it via mmap magic, then this initializer can be
826             // skipped entirely.
827             let instance = self.store.instance_mut(self.context.instance);
828             if let Some(memory_index) = self.module.defined_memory_index(memory_index) {
829                 if !instance.memories[memory_index].1.needs_init() {
830                     return true;
831                 }
832             }
833             let memory = instance.get_memory(memory_index);
834 
835             unsafe {
836                 let src = instance.wasm_data(init.data.clone());
837                 let offset = usize::try_from(init.offset).unwrap();
838                 let dst = memory.base.as_ptr().add(offset);
839 
840                 assert!(offset + src.len() <= memory.current_length());
841 
842                 // FIXME audit whether this is safe in the presence of shared
843                 // memory
844                 // (https://github.com/bytecodealliance/wasmtime/issues/4203).
845                 ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len())
846             }
847             true
848         }
849     }
850 
851     let ok = module
852         .memory_initialization
853         .init_memory(&mut InitMemoryAtInstantiation {
854             module,
855             store,
856             context,
857             const_evaluator,
858         });
859     if !ok {
860         return Err(Trap::MemoryOutOfBounds.into());
861     }
862 
863     Ok(())
864 }
865 
866 fn check_init_bounds(store: &mut StoreOpaque, instance: InstanceId, module: &Module) -> Result<()> {
867     check_table_init_bounds(store, instance, module)?;
868 
869     match &module.memory_initialization {
870         MemoryInitialization::Segmented(initializers) => {
871             check_memory_init_bounds(store, instance, initializers)?;
872         }
873         // Statically validated already to have everything in-bounds.
874         MemoryInitialization::Static { .. } => {}
875     }
876 
877     Ok(())
878 }
879 
880 fn initialize_globals(
881     store: &mut StoreOpaque,
882     context: &mut ConstEvalContext,
883     const_evaluator: &mut ConstExprEvaluator,
884     module: &Module,
885 ) -> Result<()> {
886     assert!(core::ptr::eq(
887         &**store.instance(context.instance).env_module(),
888         module
889     ));
890 
891     let mut store = AutoAssertNoGc::new(store);
892 
893     for (index, init) in module.global_initializers.iter() {
894         let raw = unsafe {
895             const_evaluator
896                 .eval(&mut store, context, init)
897                 .expect("should be a valid const expr")
898         };
899 
900         let instance = store.instance_mut(context.instance);
901         let to = instance.global_ptr(index);
902         let wasm_ty = module.globals[module.global_index(index)].wasm_ty;
903 
904         #[cfg(feature = "wmemcheck")]
905         if index.as_u32() == 0 && wasm_ty == wasmtime_environ::WasmValType::I32 {
906             if let Some(wmemcheck) = instance.wmemcheck_state_mut() {
907                 let size = usize::try_from(raw.get_i32()).unwrap();
908                 wmemcheck.set_stack_size(size);
909             }
910         }
911 
912         // This write is safe because we know we have the correct module for
913         // this instance and its vmctx due to the assert above.
914         unsafe {
915             to.write(VMGlobalDefinition::from_val_raw(&mut store, wasm_ty, raw)?);
916         };
917     }
918     Ok(())
919 }
920 
921 pub fn initialize_instance(
922     store: &mut StoreOpaque,
923     instance: InstanceId,
924     module: &Module,
925     is_bulk_memory: bool,
926 ) -> Result<()> {
927     // If bulk memory is not enabled, bounds check the data and element segments before
928     // making any changes. With bulk memory enabled, initializers are processed
929     // in-order and side effects are observed up to the point of an out-of-bounds
930     // initializer, so the early checking is not desired.
931     if !is_bulk_memory {
932         check_init_bounds(store, instance, module)?;
933     }
934 
935     let mut context = ConstEvalContext::new(instance);
936     let mut const_evaluator = ConstExprEvaluator::default();
937 
938     initialize_globals(store, &mut context, &mut const_evaluator, module)?;
939     initialize_tables(store, &mut context, &mut const_evaluator, module)?;
940     initialize_memories(store, &mut context, &mut const_evaluator, &module)?;
941 
942     Ok(())
943 }
944 
945 #[cfg(test)]
946 mod tests {
947     use super::*;
948 
949     #[test]
950     fn allocator_traits_are_object_safe() {
951         fn _instance_allocator(_: &dyn InstanceAllocatorImpl) {}
952         fn _instance_allocator_ext(_: &dyn InstanceAllocator) {}
953     }
954 }
955