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, VMStore};
9 use crate::store::{InstanceId, StoreOpaque};
10 use crate::{OpaqueRootScope, Val};
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,
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 InstanceAllocator: Send + Sync {
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<'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(&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(&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 `InstanceAllocator` 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     fn allocate_memory(
257         &self,
258         request: &mut InstanceAllocationRequest,
259         ty: &wasmtime_environ::Memory,
260         tunables: &Tunables,
261         memory_index: Option<DefinedMemoryIndex>,
262     ) -> Result<(MemoryAllocationIndex, Memory)>;
263 
264     /// Deallocate an instance's previously allocated memory.
265     ///
266     /// # Unsafety
267     ///
268     /// The memory must have previously been allocated by
269     /// `Self::allocate_memory`, be at the given index, and must currently be
270     /// allocated. It must never be used again.
271     unsafe fn deallocate_memory(
272         &self,
273         memory_index: Option<DefinedMemoryIndex>,
274         allocation_index: MemoryAllocationIndex,
275         memory: Memory,
276     );
277 
278     /// Allocate a table for an instance.
279     fn allocate_table(
280         &self,
281         req: &mut InstanceAllocationRequest,
282         table: &wasmtime_environ::Table,
283         tunables: &Tunables,
284         table_index: DefinedTableIndex,
285     ) -> Result<(TableAllocationIndex, Table)>;
286 
287     /// Deallocate an instance's previously allocated table.
288     ///
289     /// # Unsafety
290     ///
291     /// The table must have previously been allocated by `Self::allocate_table`,
292     /// be at the given index, and must currently be allocated. It must never be
293     /// used again.
294     unsafe fn deallocate_table(
295         &self,
296         table_index: DefinedTableIndex,
297         allocation_index: TableAllocationIndex,
298         table: Table,
299     );
300 
301     /// Allocates a fiber stack for calling async functions on.
302     #[cfg(feature = "async")]
303     fn allocate_fiber_stack(&self) -> Result<wasmtime_fiber::FiberStack>;
304 
305     /// Deallocates a fiber stack that was previously allocated with
306     /// `allocate_fiber_stack`.
307     ///
308     /// # Safety
309     ///
310     /// The provided stack is required to have been allocated with
311     /// `allocate_fiber_stack`.
312     #[cfg(feature = "async")]
313     unsafe fn deallocate_fiber_stack(&self, stack: wasmtime_fiber::FiberStack);
314 
315     /// Allocate a GC heap for allocating Wasm GC objects within.
316     #[cfg(feature = "gc")]
317     fn allocate_gc_heap(
318         &self,
319         engine: &crate::Engine,
320         gc_runtime: &dyn GcRuntime,
321         memory_alloc_index: MemoryAllocationIndex,
322         memory: Memory,
323     ) -> Result<(GcHeapAllocationIndex, Box<dyn GcHeap>)>;
324 
325     /// Deallocate a GC heap that was previously allocated with
326     /// `allocate_gc_heap`.
327     #[cfg(feature = "gc")]
328     #[must_use = "it is the caller's responsibility to deallocate the GC heap's underlying memory \
329                   storage after the GC heap is deallocated"]
330     fn deallocate_gc_heap(
331         &self,
332         allocation_index: GcHeapAllocationIndex,
333         gc_heap: Box<dyn GcHeap>,
334     ) -> (MemoryAllocationIndex, Memory);
335 
336     /// Purges all lingering resources related to `module` from within this
337     /// allocator.
338     ///
339     /// Primarily present for the pooling allocator to remove mappings of
340     /// this module from slots in linear memory.
341     fn purge_module(&self, module: CompiledModuleId);
342 
343     /// Use the next available protection key.
344     ///
345     /// The pooling allocator can use memory protection keys (MPK) for
346     /// compressing the guard regions protecting against OOB. Each
347     /// pool-allocated store needs its own key.
348     fn next_available_pkey(&self) -> Option<ProtectionKey>;
349 
350     /// Restrict access to memory regions protected by `pkey`.
351     ///
352     /// This is useful for the pooling allocator, which can use memory
353     /// protection keys (MPK). Note: this may still allow access to other
354     /// protection keys, such as the default kernel key; see implementations of
355     /// this.
356     fn restrict_to_pkey(&self, pkey: ProtectionKey);
357 
358     /// Allow access to memory regions protected by any protection key.
359     fn allow_all_pkeys(&self);
360 }
361 
362 impl dyn InstanceAllocator + '_ {
363     /// Allocates a fresh `InstanceHandle` for the `req` given.
364     ///
365     /// This will allocate memories and tables internally from this allocator
366     /// and weave that altogether into a final and complete `InstanceHandle`
367     /// ready to be registered with a store.
368     ///
369     /// Note that the returned instance must still have `.initialize(..)` called
370     /// on it to complete the instantiation process.
371     ///
372     /// # Safety
373     ///
374     /// The `request` provided must be valid, e.g. the imports within are
375     /// correctly sized/typed for the instance being created.
376     pub(crate) unsafe fn allocate_module(
377         &self,
378         mut request: InstanceAllocationRequest,
379     ) -> Result<InstanceHandle> {
380         let module = request.runtime_info.env_module();
381 
382         if cfg!(debug_assertions) {
383             InstanceAllocator::validate_module(self, module, request.runtime_info.offsets())
384                 .expect("module should have already been validated before allocation");
385         }
386 
387         self.increment_core_instance_count()?;
388 
389         let num_defined_memories = module.num_defined_memories();
390         let num_defined_tables = module.num_defined_tables();
391 
392         let mut guard = DeallocateOnDrop {
393             run_deallocate: true,
394             memories: PrimaryMap::with_capacity(num_defined_memories),
395             tables: PrimaryMap::with_capacity(num_defined_tables),
396             allocator: self,
397         };
398 
399         self.allocate_memories(&mut request, &mut guard.memories)?;
400         self.allocate_tables(&mut request, &mut guard.tables)?;
401         guard.run_deallocate = false;
402         // SAFETY: memories/tables were just allocated from the store within
403         // `request` and this function's own contract requires that the
404         // imports are valid.
405         return unsafe {
406             Ok(Instance::new(
407                 request,
408                 mem::take(&mut guard.memories),
409                 mem::take(&mut guard.tables),
410                 &module.memories,
411             ))
412         };
413 
414         struct DeallocateOnDrop<'a> {
415             run_deallocate: bool,
416             memories: PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
417             tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
418             allocator: &'a (dyn InstanceAllocator + 'a),
419         }
420 
421         impl Drop for DeallocateOnDrop<'_> {
422             fn drop(&mut self) {
423                 if !self.run_deallocate {
424                     return;
425                 }
426                 // SAFETY: these were previously allocated by this allocator
427                 unsafe {
428                     self.allocator.deallocate_memories(&mut self.memories);
429                     self.allocator.deallocate_tables(&mut self.tables);
430                 }
431                 self.allocator.decrement_core_instance_count();
432             }
433         }
434     }
435 
436     /// Deallocates the provided instance.
437     ///
438     /// This will null-out the pointer within `handle` and otherwise reclaim
439     /// resources such as tables, memories, and the instance memory itself.
440     ///
441     /// # Unsafety
442     ///
443     /// The instance must have previously been allocated by `Self::allocate`.
444     pub(crate) unsafe fn deallocate_module(&self, handle: &mut InstanceHandle) {
445         // SAFETY: the contract of `deallocate_*` is itself a contract of this
446         // function, that the memories/tables were previously allocated from
447         // here.
448         unsafe {
449             self.deallocate_memories(handle.get_mut().memories_mut());
450             self.deallocate_tables(handle.get_mut().tables_mut());
451         }
452 
453         self.decrement_core_instance_count();
454     }
455 
456     /// Allocate the memories for the given instance allocation request, pushing
457     /// them into `memories`.
458     fn allocate_memories(
459         &self,
460         request: &mut InstanceAllocationRequest,
461         memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
462     ) -> Result<()> {
463         let module = request.runtime_info.env_module();
464 
465         if cfg!(debug_assertions) {
466             InstanceAllocator::validate_module(self, module, request.runtime_info.offsets())
467                 .expect("module should have already been validated before allocation");
468         }
469 
470         for (memory_index, ty) in module.memories.iter().skip(module.num_imported_memories) {
471             let memory_index = module
472                 .defined_memory_index(memory_index)
473                 .expect("should be a defined memory since we skipped imported ones");
474 
475             let memory = self.allocate_memory(request, ty, request.tunables, Some(memory_index))?;
476             memories.push(memory);
477         }
478 
479         Ok(())
480     }
481 
482     /// Deallocate all the memories in the given primary map.
483     ///
484     /// # Unsafety
485     ///
486     /// The memories must have previously been allocated by
487     /// `Self::allocate_memories`.
488     unsafe fn deallocate_memories(
489         &self,
490         memories: &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
491     ) {
492         for (memory_index, (allocation_index, memory)) in mem::take(memories) {
493             // Because deallocating memory is infallible, we don't need to worry
494             // about leaking subsequent memories if the first memory failed to
495             // deallocate. If deallocating memory ever becomes fallible, we will
496             // need to be careful here!
497             //
498             // SAFETY: the unsafe contract here is the same as the unsafe
499             // contract of this function, that the memories were previously
500             // allocated by this allocator.
501             unsafe {
502                 self.deallocate_memory(Some(memory_index), allocation_index, memory);
503             }
504         }
505     }
506 
507     /// Allocate tables for the given instance allocation request, pushing them
508     /// into `tables`.
509     fn allocate_tables(
510         &self,
511         request: &mut InstanceAllocationRequest,
512         tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
513     ) -> Result<()> {
514         let module = request.runtime_info.env_module();
515 
516         if cfg!(debug_assertions) {
517             InstanceAllocator::validate_module(self, module, request.runtime_info.offsets())
518                 .expect("module should have already been validated before allocation");
519         }
520 
521         for (index, table) in module.tables.iter().skip(module.num_imported_tables) {
522             let def_index = module
523                 .defined_table_index(index)
524                 .expect("should be a defined table since we skipped imported ones");
525 
526             let table = self.allocate_table(request, table, request.tunables, def_index)?;
527             tables.push(table);
528         }
529 
530         Ok(())
531     }
532 
533     /// Deallocate all the tables in the given primary map.
534     ///
535     /// # Unsafety
536     ///
537     /// The tables must have previously been allocated by
538     /// `Self::allocate_tables`.
539     unsafe fn deallocate_tables(
540         &self,
541         tables: &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
542     ) {
543         for (table_index, (allocation_index, table)) in mem::take(tables) {
544             // SAFETY: the tables here were allocated from this allocator per
545             // the contract on this function itself.
546             unsafe {
547                 self.deallocate_table(table_index, allocation_index, table);
548             }
549         }
550     }
551 }
552 
553 fn check_table_init_bounds(
554     store: &mut StoreOpaque,
555     instance: InstanceId,
556     module: &Module,
557 ) -> Result<()> {
558     let mut const_evaluator = ConstExprEvaluator::default();
559     let mut store = OpaqueRootScope::new(store);
560 
561     for segment in module.table_initialization.segments.iter() {
562         let mut context = ConstEvalContext::new(instance);
563         let start = const_evaluator
564             .eval_int(&mut store, &mut context, &segment.offset)
565             .expect("const expression should be valid");
566         let start = usize::try_from(start.unwrap_i32().cast_unsigned()).unwrap();
567         let end = start.checked_add(usize::try_from(segment.elements.len()).unwrap());
568 
569         let table = store.instance_mut(instance).get_table(segment.table_index);
570         match end {
571             Some(end) if end <= table.size() => {
572                 // Initializer is in bounds
573             }
574             _ => {
575                 bail!("table out of bounds: elements segment does not fit")
576             }
577         }
578     }
579 
580     Ok(())
581 }
582 
583 async fn initialize_tables(
584     store: &mut StoreOpaque,
585     context: &mut ConstEvalContext,
586     const_evaluator: &mut ConstExprEvaluator,
587     module: &Module,
588 ) -> Result<()> {
589     let mut store = OpaqueRootScope::new(store);
590     for (table, init) in module.table_initialization.initial_values.iter() {
591         match init {
592             // Tables are always initially null-initialized at this time
593             TableInitialValue::Null { precomputed: _ } => {}
594 
595             TableInitialValue::Expr(expr) => {
596                 let init = const_evaluator
597                     .eval(&mut store, context, expr)
598                     .await
599                     .expect("const expression should be valid");
600                 let idx = module.table_index(table);
601                 let id = store.id();
602                 let table = store
603                     .instance_mut(context.instance)
604                     .get_exported_table(id, idx);
605                 let size = table._size(&store);
606                 table._fill(&mut store, 0, init.ref_().unwrap(), size)?;
607             }
608         }
609     }
610 
611     // Note: if the module's table initializer state is in
612     // FuncTable mode, we will lazily initialize tables based on
613     // any statically-precomputed image of FuncIndexes, but there
614     // may still be "leftover segments" that could not be
615     // incorporated. So we have a unified handler here that
616     // iterates over all segments (Segments mode) or leftover
617     // segments (FuncTable mode) to initialize.
618     for segment in module.table_initialization.segments.iter() {
619         let start = const_evaluator
620             .eval_int(&mut store, context, &segment.offset)
621             .expect("const expression should be valid");
622         let start = get_index(
623             start,
624             store.instance(context.instance).env_module().tables[segment.table_index].idx_type,
625         );
626         Instance::table_init_segment(
627             &mut store,
628             context.instance,
629             const_evaluator,
630             segment.table_index,
631             &segment.elements,
632             start,
633             0,
634             segment.elements.len(),
635         )
636         .await?;
637     }
638 
639     Ok(())
640 }
641 
642 fn get_index(val: &Val, ty: wasmtime_environ::IndexType) -> u64 {
643     match ty {
644         wasmtime_environ::IndexType::I32 => val.unwrap_i32().cast_unsigned().into(),
645         wasmtime_environ::IndexType::I64 => val.unwrap_i64().cast_unsigned(),
646     }
647 }
648 
649 fn get_memory_init_start(
650     store: &mut StoreOpaque,
651     init: &MemoryInitializer,
652     instance: InstanceId,
653 ) -> Result<u64> {
654     let mut context = ConstEvalContext::new(instance);
655     let mut const_evaluator = ConstExprEvaluator::default();
656     let mut store = OpaqueRootScope::new(store);
657     const_evaluator
658         .eval_int(&mut store, &mut context, &init.offset)
659         .map(|v| {
660             get_index(
661                 v,
662                 store.instance(instance).env_module().memories[init.memory_index].idx_type,
663             )
664         })
665 }
666 
667 fn check_memory_init_bounds(
668     store: &mut StoreOpaque,
669     instance: InstanceId,
670     initializers: &[MemoryInitializer],
671 ) -> Result<()> {
672     for init in initializers {
673         let memory = store.instance_mut(instance).get_memory(init.memory_index);
674         let start = get_memory_init_start(store, init, instance)?;
675         let end = usize::try_from(start)
676             .ok()
677             .and_then(|start| start.checked_add(init.data.len()));
678 
679         match end {
680             Some(end) if end <= memory.current_length() => {
681                 // Initializer is in bounds
682             }
683             _ => {
684                 bail!("memory out of bounds: data segment does not fit")
685             }
686         }
687     }
688 
689     Ok(())
690 }
691 
692 fn initialize_memories(
693     store: &mut StoreOpaque,
694     context: &mut ConstEvalContext,
695     const_evaluator: &mut ConstExprEvaluator,
696     module: &Module,
697 ) -> Result<()> {
698     // Delegates to the `init_memory` method which is sort of a duplicate of
699     // `instance.memory_init_segment` but is used at compile-time in other
700     // contexts so is shared here to have only one method of memory
701     // initialization.
702     //
703     // This call to `init_memory` notably implements all the bells and whistles
704     // so errors only happen if an out-of-bounds segment is found, in which case
705     // a trap is returned.
706 
707     struct InitMemoryAtInstantiation<'a> {
708         module: &'a Module,
709         store: &'a mut StoreOpaque,
710         context: &'a mut ConstEvalContext,
711         const_evaluator: &'a mut ConstExprEvaluator,
712     }
713 
714     impl InitMemory for InitMemoryAtInstantiation<'_> {
715         fn memory_size_in_bytes(
716             &mut self,
717             memory: wasmtime_environ::MemoryIndex,
718         ) -> Result<u64, SizeOverflow> {
719             let len = self
720                 .store
721                 .instance(self.context.instance)
722                 .get_memory(memory)
723                 .current_length();
724             let len = u64::try_from(len).unwrap();
725             Ok(len)
726         }
727 
728         fn eval_offset(
729             &mut self,
730             memory: wasmtime_environ::MemoryIndex,
731             expr: &wasmtime_environ::ConstExpr,
732         ) -> Option<u64> {
733             let mut store = OpaqueRootScope::new(&mut *self.store);
734             let val = self
735                 .const_evaluator
736                 .eval_int(&mut store, self.context, expr)
737                 .expect("const expression should be valid");
738             Some(get_index(
739                 val,
740                 store.instance(self.context.instance).env_module().memories[memory].idx_type,
741             ))
742         }
743 
744         fn write(
745             &mut self,
746             memory_index: wasmtime_environ::MemoryIndex,
747             init: &wasmtime_environ::StaticMemoryInitializer,
748         ) -> bool {
749             // If this initializer applies to a defined memory but that memory
750             // doesn't need initialization, due to something like copy-on-write
751             // pre-initializing it via mmap magic, then this initializer can be
752             // skipped entirely.
753             let instance = self.store.instance_mut(self.context.instance);
754             if let Some(memory_index) = self.module.defined_memory_index(memory_index) {
755                 if !instance.memories[memory_index].1.needs_init() {
756                     return true;
757                 }
758             }
759             let memory = instance.get_memory(memory_index);
760 
761             unsafe {
762                 let src = instance.wasm_data(init.data.clone());
763                 let offset = usize::try_from(init.offset).unwrap();
764                 let dst = memory.base.as_ptr().add(offset);
765 
766                 assert!(offset + src.len() <= memory.current_length());
767 
768                 // FIXME audit whether this is safe in the presence of shared
769                 // memory
770                 // (https://github.com/bytecodealliance/wasmtime/issues/4203).
771                 ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len())
772             }
773             true
774         }
775     }
776 
777     let ok = module
778         .memory_initialization
779         .init_memory(&mut InitMemoryAtInstantiation {
780             module,
781             store,
782             context,
783             const_evaluator,
784         });
785     if !ok {
786         return Err(Trap::MemoryOutOfBounds.into());
787     }
788 
789     Ok(())
790 }
791 
792 fn check_init_bounds(store: &mut StoreOpaque, instance: InstanceId, module: &Module) -> Result<()> {
793     check_table_init_bounds(store, instance, module)?;
794 
795     match &module.memory_initialization {
796         MemoryInitialization::Segmented(initializers) => {
797             check_memory_init_bounds(store, instance, initializers)?;
798         }
799         // Statically validated already to have everything in-bounds.
800         MemoryInitialization::Static { .. } => {}
801     }
802 
803     Ok(())
804 }
805 
806 async fn initialize_globals(
807     store: &mut StoreOpaque,
808     context: &mut ConstEvalContext,
809     const_evaluator: &mut ConstExprEvaluator,
810     module: &Module,
811 ) -> Result<()> {
812     assert!(core::ptr::eq(
813         &**store.instance(context.instance).env_module(),
814         module
815     ));
816 
817     let mut store = OpaqueRootScope::new(store);
818 
819     for (index, init) in module.global_initializers.iter() {
820         // Attempt a simple, synchronous evaluation before hitting the
821         // general-purpose `.await` point below. This benchmarks ~15% faster in
822         // instantiation vs just falling through to `.await` below.
823         let val = if let Some(val) = const_evaluator.try_simple(init) {
824             val
825         } else {
826             const_evaluator
827                 .eval(&mut store, context, init)
828                 .await
829                 .expect("should be a valid const expr")
830         };
831 
832         let id = store.id();
833         let index = module.global_index(index);
834         let mut instance = store.instance_mut(context.instance);
835 
836         #[cfg(feature = "wmemcheck")]
837         if index.as_u32() == 0
838             && module.globals[index].wasm_ty == wasmtime_environ::WasmValType::I32
839         {
840             if let Some(wmemcheck) = instance.as_mut().wmemcheck_state_mut() {
841                 let size = usize::try_from(val.unwrap_i32()).unwrap();
842                 wmemcheck.set_stack_size(size);
843             }
844         }
845 
846         let global = instance.as_mut().get_exported_global(id, index);
847 
848         // Note that mutability is bypassed here because this is, by definition,
849         // initialization of globals meaning that if it's an immutable global
850         // this is the one and only write.
851         //
852         // SAFETY: this is a valid module so `val` should have the correct type
853         // for this global, and it's safe to write to a global for the first
854         // time as-is happening here.
855         unsafe {
856             global.set_unchecked(&mut store, &val)?;
857         }
858     }
859     Ok(())
860 }
861 
862 pub async fn initialize_instance(
863     store: &mut StoreOpaque,
864     instance: InstanceId,
865     module: &Module,
866     is_bulk_memory: bool,
867 ) -> Result<()> {
868     // If bulk memory is not enabled, bounds check the data and element segments before
869     // making any changes. With bulk memory enabled, initializers are processed
870     // in-order and side effects are observed up to the point of an out-of-bounds
871     // initializer, so the early checking is not desired.
872     if !is_bulk_memory {
873         check_init_bounds(store, instance, module)?;
874     }
875 
876     let mut context = ConstEvalContext::new(instance);
877     let mut const_evaluator = ConstExprEvaluator::default();
878 
879     initialize_globals(store, &mut context, &mut const_evaluator, module).await?;
880     initialize_tables(store, &mut context, &mut const_evaluator, module).await?;
881     initialize_memories(store, &mut context, &mut const_evaluator, &module)?;
882 
883     Ok(())
884 }
885 
886 #[cfg(test)]
887 mod tests {
888     use super::*;
889 
890     #[test]
891     fn allocator_traits_are_object_safe() {
892         fn _instance_allocator(_: &dyn InstanceAllocator) {}
893     }
894 }
895