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