wasmer_vm/instance/
mod.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4//! An `Instance` contains all the runtime state used by execution of
5//! a WebAssembly module (except its callstack and register state). An
6//! `VMInstance` is a wrapper around `Instance` that manages
7//! how it is allocated and deallocated.
8
9mod allocator;
10
11use crate::LinearMemory;
12use crate::imports::Imports;
13use crate::store::{InternalStoreHandle, StoreObjects};
14use crate::table::TableElement;
15use crate::trap::{Trap, TrapCode};
16use crate::vmcontext::{
17    VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionContext,
18    VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition,
19    VMMemoryImport, VMSharedTagIndex, VMSignatureHash, VMTableDefinition, VMTableImport,
20    VMTrampoline, memory_copy, memory_fill, memory32_atomic_check32, memory32_atomic_check64,
21};
22use crate::{FunctionBodyPtr, MaybeInstanceOwned, TrapHandlerFn, VMTag, wasmer_call_trampoline};
23use crate::{VMConfig, VMFuncRef, VMFunction, VMGlobal, VMMemory, VMTable};
24use crate::{export::VMExtern, threadconditions::ExpectedValue};
25pub use allocator::InstanceAllocator;
26use core::mem::offset_of;
27use itertools::Itertools;
28use more_asserts::assert_lt;
29use std::alloc::Layout;
30use std::cell::RefCell;
31use std::collections::HashMap;
32use std::convert::TryFrom;
33use std::fmt;
34use std::mem;
35use std::ptr::{self, NonNull};
36use std::slice;
37use std::sync::Arc;
38use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap, packed_option::ReservedValue};
39use wasmer_types::{
40    DataIndex, DataInitializer, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, GlobalInit,
41    InitExpr, InitExprOp, LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex,
42    MemoryError, MemoryIndex, ModuleInfo, Pages, RawValue, SignatureIndex, TableIndex, TagIndex,
43    VMOffsets,
44};
45
46/// A WebAssembly instance.
47///
48/// The type is dynamically-sized. Indeed, the `vmctx` field can
49/// contain various data. That's why the type has a C representation
50/// to ensure that the `vmctx` field is last. See the documentation of
51/// the `vmctx` field to learn more.
52#[repr(C)]
53#[allow(clippy::type_complexity)]
54pub(crate) struct Instance {
55    /// The `ModuleInfo` this `Instance` was instantiated from.
56    module: Arc<ModuleInfo>,
57
58    /// Pointer to the object store of the context owning this instance.
59    context: *mut StoreObjects,
60
61    /// Offsets in the `vmctx` region.
62    offsets: VMOffsets,
63
64    /// WebAssembly linear memory data.
65    memories: BoxedSlice<LocalMemoryIndex, InternalStoreHandle<VMMemory>>,
66
67    /// WebAssembly table data.
68    tables: BoxedSlice<LocalTableIndex, InternalStoreHandle<VMTable>>,
69
70    /// WebAssembly global data.
71    globals: BoxedSlice<LocalGlobalIndex, InternalStoreHandle<VMGlobal>>,
72
73    /// WebAssembly tag data. Notably, this stores *all* tags, not just local ones.
74    tags: BoxedSlice<TagIndex, InternalStoreHandle<VMTag>>,
75
76    /// Pointers to functions in executable memory.
77    functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
78
79    /// Pointers to function call trampolines in executable memory.
80    function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
81
82    /// Passive elements in this instantiation. As `elem.drop`s happen, these
83    /// entries get removed.
84    passive_elements: RefCell<HashMap<ElemIndex, Box<[Option<VMFuncRef>]>>>,
85
86    /// Per-instance view of the module's passive data segments.
87    ///
88    /// A `None` entry (dropped) or a missing entry is treated as an empty slice.
89    ///
90    /// The bytes are shared with the module via `Arc` (no per-instance copy).
91    /// `data.drop` replaces an entry's value with `None` to mark the segment
92    /// unusable for subsequent `memory.init` on this instance, without
93    /// affecting the shared module bytes or any other instance.
94    passive_data: RefCell<HashMap<DataIndex, Option<Arc<[u8]>>>>,
95
96    /// Mapping of function indices to their func ref backing data. `VMFuncRef`s
97    /// will point to elements here for functions defined by this instance.
98    funcrefs: BoxedSlice<LocalFunctionIndex, VMCallerCheckedAnyfunc>,
99
100    /// Mapping of function indices to their func ref backing data. `VMFuncRef`s
101    /// will point to elements here for functions imported by this instance.
102    imported_funcrefs: BoxedSlice<FunctionIndex, NonNull<VMCallerCheckedAnyfunc>>,
103
104    /// Additional context used by compiled WebAssembly code. This
105    /// field is last, and represents a dynamically-sized array that
106    /// extends beyond the nominal end of the struct (similar to a
107    /// flexible array member).
108    vmctx: VMContext,
109}
110
111impl fmt::Debug for Instance {
112    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
113        formatter.debug_struct("Instance").finish()
114    }
115}
116
117#[allow(clippy::cast_ptr_alignment)]
118impl Instance {
119    /// Helper function to access various locations offset from our `*mut
120    /// VMContext` object.
121    unsafe fn vmctx_plus_offset<T>(&self, offset: u32) -> *mut T {
122        unsafe {
123            (self.vmctx_ptr() as *mut u8)
124                .add(usize::try_from(offset).unwrap())
125                .cast()
126        }
127    }
128
129    fn module(&self) -> &Arc<ModuleInfo> {
130        &self.module
131    }
132
133    pub(crate) fn module_ref(&self) -> &ModuleInfo {
134        &self.module
135    }
136
137    pub(crate) fn context(&self) -> &StoreObjects {
138        unsafe { &*self.context }
139    }
140
141    pub(crate) fn context_mut(&mut self) -> &mut StoreObjects {
142        unsafe { &mut *self.context }
143    }
144
145    /// Offsets in the `vmctx` region.
146    fn offsets(&self) -> &VMOffsets {
147        &self.offsets
148    }
149
150    /// Return the indexed `VMFunctionImport`.
151    fn imported_function(&self, index: FunctionIndex) -> &VMFunctionImport {
152        let index = usize::try_from(index.as_u32()).unwrap();
153        unsafe { &*self.imported_functions_ptr().add(index) }
154    }
155
156    /// Return a pointer to the `VMFunctionImport`s.
157    fn imported_functions_ptr(&self) -> *mut VMFunctionImport {
158        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_functions_begin()) }
159    }
160
161    /// Return the index `VMTableImport`.
162    fn imported_table(&self, index: TableIndex) -> &VMTableImport {
163        let index = usize::try_from(index.as_u32()).unwrap();
164        unsafe { &*self.imported_tables_ptr().add(index) }
165    }
166
167    /// Return a pointer to the `VMTableImports`s.
168    fn imported_tables_ptr(&self) -> *mut VMTableImport {
169        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_tables_begin()) }
170    }
171
172    /// Return the indexed `VMMemoryImport`.
173    fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport {
174        let index = usize::try_from(index.as_u32()).unwrap();
175        unsafe { &*self.imported_memories_ptr().add(index) }
176    }
177
178    /// Return a pointer to the `VMMemoryImport`s.
179    fn imported_memories_ptr(&self) -> *mut VMMemoryImport {
180        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_memories_begin()) }
181    }
182
183    /// Return the indexed `VMGlobalImport`.
184    fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport {
185        let index = usize::try_from(index.as_u32()).unwrap();
186        unsafe { &*self.imported_globals_ptr().add(index) }
187    }
188
189    /// Return a pointer to the `VMGlobalImport`s.
190    fn imported_globals_ptr(&self) -> *mut VMGlobalImport {
191        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_globals_begin()) }
192    }
193
194    /// Return the indexed `VMSharedTagIndex`.
195    #[cfg_attr(target_os = "windows", allow(dead_code))]
196    pub(crate) fn shared_tag_ptr(&self, index: TagIndex) -> &VMSharedTagIndex {
197        let index = usize::try_from(index.as_u32()).unwrap();
198        unsafe { &*self.shared_tags_ptr().add(index) }
199    }
200
201    /// Return a pointer to the `VMSharedTagIndex`s.
202    pub(crate) fn shared_tags_ptr(&self) -> *mut VMSharedTagIndex {
203        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_tag_ids_begin()) }
204    }
205
206    /// Return the indexed `VMTableDefinition`.
207    #[allow(dead_code)]
208    fn table(&self, index: LocalTableIndex) -> VMTableDefinition {
209        unsafe { *self.table_ptr(index).as_ref() }
210    }
211
212    #[allow(dead_code)]
213    /// Updates the value for a defined table to `VMTableDefinition`.
214    fn set_table(&self, index: LocalTableIndex, table: &VMTableDefinition) {
215        unsafe {
216            *self.table_ptr(index).as_ptr() = *table;
217        }
218    }
219
220    /// Return the indexed `VMTableDefinition`.
221    fn table_ptr(&self, index: LocalTableIndex) -> NonNull<VMTableDefinition> {
222        let index = usize::try_from(index.as_u32()).unwrap();
223        NonNull::new(unsafe { self.tables_ptr().add(index) }).unwrap()
224    }
225
226    /// Return a pointer to the `VMTableDefinition`s.
227    fn tables_ptr(&self) -> *mut VMTableDefinition {
228        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_tables_begin()) }
229    }
230
231    fn fixed_funcref_table_ptr(
232        &self,
233        index: LocalTableIndex,
234    ) -> Option<NonNull<VMCallerCheckedAnyfunc>> {
235        let offset = self.offsets.vmctx_fixed_funcref_table_anyfuncs(index)?;
236        Some(NonNull::new(unsafe { self.vmctx_plus_offset(offset) }).unwrap())
237    }
238
239    fn sync_fixed_funcref_table_element(
240        &self,
241        table_index: LocalTableIndex,
242        index: u32,
243        funcref: Option<VMFuncRef>,
244    ) {
245        let Some(base) = self.fixed_funcref_table_ptr(table_index) else {
246            return;
247        };
248        unsafe {
249            *base.as_ptr().add(index as usize) = anyfunc_from_funcref(funcref);
250        }
251    }
252
253    fn sync_fixed_funcref_table(&self, table_index: LocalTableIndex) {
254        let Some(base) = self.fixed_funcref_table_ptr(table_index) else {
255            return;
256        };
257        let table = self.tables[table_index].get(self.context());
258        for index in 0..table.size() {
259            let TableElement::FuncRef(funcref) = table.get(index).unwrap() else {
260                unreachable!("fixed funcref tables cannot contain externrefs");
261            };
262            unsafe {
263                *base.as_ptr().add(index as usize) = anyfunc_from_funcref(funcref);
264            }
265        }
266    }
267
268    fn sync_fixed_funcref_table_by_index(&self, table_index: TableIndex) {
269        if let Some(local_table_index) = self.module.local_table_index(table_index) {
270            self.sync_fixed_funcref_table(local_table_index);
271        }
272    }
273
274    #[allow(dead_code)]
275    /// Get a locally defined or imported memory.
276    fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinition {
277        if let Some(local_index) = self.module.local_memory_index(index) {
278            self.memory(local_index)
279        } else {
280            let import = self.imported_memory(index);
281            unsafe { *import.definition.as_ref() }
282        }
283    }
284
285    /// Return the indexed `VMMemoryDefinition`.
286    fn memory(&self, index: LocalMemoryIndex) -> VMMemoryDefinition {
287        unsafe { *self.memory_ptr(index).as_ref() }
288    }
289
290    #[allow(dead_code)]
291    /// Set the indexed memory to `VMMemoryDefinition`.
292    fn set_memory(&self, index: LocalMemoryIndex, mem: &VMMemoryDefinition) {
293        unsafe {
294            *self.memory_ptr(index).as_ptr() = *mem;
295        }
296    }
297
298    /// Return the indexed `VMMemoryDefinition`.
299    fn memory_ptr(&self, index: LocalMemoryIndex) -> NonNull<VMMemoryDefinition> {
300        let index = usize::try_from(index.as_u32()).unwrap();
301        NonNull::new(unsafe { self.memories_ptr().add(index) }).unwrap()
302    }
303
304    /// Return a pointer to the `VMMemoryDefinition`s.
305    fn memories_ptr(&self) -> *mut VMMemoryDefinition {
306        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_memories_begin()) }
307    }
308
309    /// Get a locally defined or imported memory.
310    fn get_vmmemory(&self, index: MemoryIndex) -> &VMMemory {
311        if let Some(local_index) = self.module.local_memory_index(index) {
312            unsafe {
313                self.memories
314                    .get(local_index)
315                    .unwrap()
316                    .get(self.context.as_ref().unwrap())
317            }
318        } else {
319            let import = self.imported_memory(index);
320            unsafe { import.handle.get(self.context.as_ref().unwrap()) }
321        }
322    }
323
324    /// Get a locally defined or imported memory.
325    fn get_vmmemory_mut(&mut self, index: MemoryIndex) -> &mut VMMemory {
326        if let Some(local_index) = self.module.local_memory_index(index) {
327            unsafe {
328                self.memories
329                    .get_mut(local_index)
330                    .unwrap()
331                    .get_mut(self.context.as_mut().unwrap())
332            }
333        } else {
334            let import = self.imported_memory(index);
335            unsafe { import.handle.get_mut(self.context.as_mut().unwrap()) }
336        }
337    }
338
339    /// Get a locally defined memory as mutable.
340    fn get_local_vmmemory_mut(&mut self, local_index: LocalMemoryIndex) -> &mut VMMemory {
341        unsafe {
342            self.memories
343                .get_mut(local_index)
344                .unwrap()
345                .get_mut(self.context.as_mut().unwrap())
346        }
347    }
348
349    /// Return the indexed `VMGlobalDefinition`.
350    fn global(&self, index: LocalGlobalIndex) -> VMGlobalDefinition {
351        unsafe { self.global_ptr(index).as_ref().clone() }
352    }
353
354    /// Set the indexed global to `VMGlobalDefinition`.
355    #[allow(dead_code)]
356    fn set_global(&self, index: LocalGlobalIndex, global: &VMGlobalDefinition) {
357        unsafe {
358            *self.global_ptr(index).as_ptr() = global.clone();
359        }
360    }
361
362    /// Return the indexed `VMGlobalDefinition`.
363    fn global_ptr(&self, index: LocalGlobalIndex) -> NonNull<VMGlobalDefinition> {
364        let index = usize::try_from(index.as_u32()).unwrap();
365        NonNull::new(unsafe { self.globals_ptr().add(index) }).unwrap()
366    }
367
368    /// Return a pointer to the `VMGlobalDefinition`s.
369    fn globals_ptr(&self) -> *mut VMGlobalDefinition {
370        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_globals_begin()) }
371    }
372
373    /// Return a pointer to the `VMBuiltinFunctionsArray`.
374    fn builtin_functions_ptr(&self) -> *mut VMBuiltinFunctionsArray {
375        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_builtin_functions_begin()) }
376    }
377
378    /// Return a reference to the vmctx used by compiled wasm code.
379    fn vmctx(&self) -> &VMContext {
380        &self.vmctx
381    }
382
383    /// Return a raw pointer to the vmctx used by compiled wasm code.
384    fn vmctx_ptr(&self) -> *mut VMContext {
385        self.vmctx() as *const VMContext as *mut VMContext
386    }
387
388    /// Invoke the WebAssembly start function of the instance, if one is present.
389    fn invoke_start_function(
390        &self,
391        config: &VMConfig,
392        trap_handler: Option<*const TrapHandlerFn<'static>>,
393    ) -> Result<(), Trap> {
394        let start_index = match self.module.start_function {
395            Some(idx) => idx,
396            None => return Ok(()),
397        };
398
399        let (callee_address, callee_vmctx) = match self.module.local_func_index(start_index) {
400            Some(local_index) => {
401                let body = self
402                    .functions
403                    .get(local_index)
404                    .expect("function index is out of bounds")
405                    .0;
406                (
407                    body as *const _,
408                    VMFunctionContext {
409                        vmctx: self.vmctx_ptr(),
410                    },
411                )
412            }
413            None => {
414                assert_lt!(start_index.index(), self.module.num_imported_functions);
415                let import = self.imported_function(start_index);
416                (import.body, import.environment)
417            }
418        };
419
420        let sig = self.module.functions[start_index];
421        let trampoline = self.function_call_trampolines[sig];
422        let mut values_vec = vec![];
423
424        unsafe {
425            // Even though we already know the type of the function we need to call, in certain
426            // specific cases trampoline prepare callee arguments for specific optimizations, such
427            // as passing g0 and m0_base_ptr as parameters.
428            wasmer_call_trampoline(
429                trap_handler,
430                config,
431                callee_vmctx,
432                trampoline,
433                callee_address,
434                values_vec.as_mut_ptr(),
435            )
436        }
437    }
438
439    /// Return the offset from the vmctx pointer to its containing `Instance`.
440    #[inline]
441    pub(crate) fn vmctx_offset() -> isize {
442        offset_of!(Self, vmctx) as isize
443    }
444
445    /// Return the table index for the given `VMTableDefinition`.
446    pub(crate) fn table_index(&self, table: &VMTableDefinition) -> LocalTableIndex {
447        let begin: *const VMTableDefinition = self.tables_ptr() as *const _;
448        let end: *const VMTableDefinition = table;
449        // TODO: Use `offset_from` once it stabilizes.
450        let index = LocalTableIndex::new(
451            (end as usize - begin as usize) / mem::size_of::<VMTableDefinition>(),
452        );
453        assert_lt!(index.index(), self.tables.len());
454        index
455    }
456
457    /// Return the memory index for the given `VMMemoryDefinition`.
458    pub(crate) fn memory_index(&self, memory: &VMMemoryDefinition) -> LocalMemoryIndex {
459        let begin: *const VMMemoryDefinition = self.memories_ptr() as *const _;
460        let end: *const VMMemoryDefinition = memory;
461        // TODO: Use `offset_from` once it stabilizes.
462        let index = LocalMemoryIndex::new(
463            (end as usize - begin as usize) / mem::size_of::<VMMemoryDefinition>(),
464        );
465        assert_lt!(index.index(), self.memories.len());
466        index
467    }
468
469    /// Grow memory by the specified amount of pages.
470    ///
471    /// Returns `None` if memory can't be grown by the specified amount
472    /// of pages.
473    pub(crate) fn memory_grow<IntoPages>(
474        &mut self,
475        memory_index: LocalMemoryIndex,
476        delta: IntoPages,
477    ) -> Result<Pages, MemoryError>
478    where
479        IntoPages: Into<Pages>,
480    {
481        let mem = *self
482            .memories
483            .get(memory_index)
484            .unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()));
485        mem.get_mut(self.context_mut()).grow(delta.into())
486    }
487
488    /// Grow imported memory by the specified amount of pages.
489    ///
490    /// Returns `None` if memory can't be grown by the specified amount
491    /// of pages.
492    ///
493    /// # Safety
494    /// This and `imported_memory_size` are currently unsafe because they
495    /// dereference the memory import's pointers.
496    pub(crate) unsafe fn imported_memory_grow<IntoPages>(
497        &mut self,
498        memory_index: MemoryIndex,
499        delta: IntoPages,
500    ) -> Result<Pages, MemoryError>
501    where
502        IntoPages: Into<Pages>,
503    {
504        let import = self.imported_memory(memory_index);
505        let mem = import.handle;
506        mem.get_mut(self.context_mut()).grow(delta.into())
507    }
508
509    /// Returns the number of allocated wasm pages.
510    pub(crate) fn memory_size(&self, memory_index: LocalMemoryIndex) -> Pages {
511        let mem = *self
512            .memories
513            .get(memory_index)
514            .unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()));
515        mem.get(self.context()).size()
516    }
517
518    /// Returns the number of allocated wasm pages in an imported memory.
519    ///
520    /// # Safety
521    /// This and `imported_memory_grow` are currently unsafe because they
522    /// dereference the memory import's pointers.
523    pub(crate) unsafe fn imported_memory_size(&self, memory_index: MemoryIndex) -> Pages {
524        let import = self.imported_memory(memory_index);
525        let mem = import.handle;
526        mem.get(self.context()).size()
527    }
528
529    /// Returns the number of elements in a given table.
530    pub(crate) fn table_size(&self, table_index: LocalTableIndex) -> u32 {
531        let table = self
532            .tables
533            .get(table_index)
534            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()));
535        table.get(self.context()).size()
536    }
537
538    /// Returns the number of elements in a given imported table.
539    ///
540    /// # Safety
541    /// `table_index` must be a valid, imported table index.
542    pub(crate) unsafe fn imported_table_size(&self, table_index: TableIndex) -> u32 {
543        let import = self.imported_table(table_index);
544        let table = import.handle;
545        table.get(self.context()).size()
546    }
547
548    /// Grow table by the specified amount of elements.
549    ///
550    /// Returns `None` if table can't be grown by the specified amount
551    /// of elements.
552    pub(crate) fn table_grow(
553        &mut self,
554        table_index: LocalTableIndex,
555        delta: u32,
556        init_value: TableElement,
557    ) -> Option<u32> {
558        let table = *self
559            .tables
560            .get(table_index)
561            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()));
562        table.get_mut(self.context_mut()).grow(delta, init_value)
563    }
564
565    /// Grow table by the specified amount of elements.
566    ///
567    /// # Safety
568    /// `table_index` must be a valid, imported table index.
569    pub(crate) unsafe fn imported_table_grow(
570        &mut self,
571        table_index: TableIndex,
572        delta: u32,
573        init_value: TableElement,
574    ) -> Option<u32> {
575        let import = self.imported_table(table_index);
576        let table = import.handle;
577        table.get_mut(self.context_mut()).grow(delta, init_value)
578    }
579
580    /// Get table element by index.
581    pub(crate) fn table_get(
582        &self,
583        table_index: LocalTableIndex,
584        index: u32,
585    ) -> Option<TableElement> {
586        let table = self
587            .tables
588            .get(table_index)
589            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()));
590        table.get(self.context()).get(index)
591    }
592
593    /// Returns the element at the given index.
594    ///
595    /// # Safety
596    /// `table_index` must be a valid, imported table index.
597    pub(crate) unsafe fn imported_table_get(
598        &self,
599        table_index: TableIndex,
600        index: u32,
601    ) -> Option<TableElement> {
602        let import = self.imported_table(table_index);
603        let table = import.handle;
604        table.get(self.context()).get(index)
605    }
606
607    /// Set table element by index.
608    pub(crate) fn table_set(
609        &mut self,
610        table_index: LocalTableIndex,
611        index: u32,
612        val: TableElement,
613    ) -> Result<(), Trap> {
614        let table = *self
615            .tables
616            .get(table_index)
617            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()));
618        let funcref = match &val {
619            TableElement::FuncRef(funcref) => Some(*funcref),
620            TableElement::ExternRef(_) => None,
621        };
622        table.get_mut(self.context_mut()).set(index, val)?;
623        if let Some(funcref) = funcref {
624            self.sync_fixed_funcref_table_element(table_index, index, funcref);
625        }
626        Ok(())
627    }
628
629    /// Set table element by index for an imported table.
630    ///
631    /// # Safety
632    /// `table_index` must be a valid, imported table index.
633    pub(crate) unsafe fn imported_table_set(
634        &mut self,
635        table_index: TableIndex,
636        index: u32,
637        val: TableElement,
638    ) -> Result<(), Trap> {
639        let import = self.imported_table(table_index);
640        let table = import.handle;
641        table.get_mut(self.context_mut()).set(index, val)
642    }
643
644    /// Get a `VMFuncRef` for the given `FunctionIndex`.
645    pub(crate) fn func_ref(&self, function_index: FunctionIndex) -> Option<VMFuncRef> {
646        if function_index == FunctionIndex::reserved_value() {
647            None
648        } else if let Some(local_function_index) = self.module.local_func_index(function_index) {
649            Some(VMFuncRef(NonNull::from(
650                &self.funcrefs[local_function_index],
651            )))
652        } else {
653            Some(VMFuncRef(self.imported_funcrefs[function_index]))
654        }
655    }
656
657    /// The `table.init` operation: initializes a portion of a table with a
658    /// passive element.
659    ///
660    /// # Errors
661    ///
662    /// Returns a `Trap` error when the range within the table is out of bounds
663    /// or the range within the passive element is out of bounds.
664    pub(crate) fn table_init(
665        &mut self,
666        table_index: TableIndex,
667        elem_index: ElemIndex,
668        dst: u32,
669        src: u32,
670        len: u32,
671    ) -> Result<(), Trap> {
672        // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init
673
674        let table = self.get_table_handle(table_index);
675        let table = unsafe { table.get_mut(&mut *self.context) };
676        let passive_elements = self.passive_elements.borrow();
677        let elem = passive_elements
678            .get(&elem_index)
679            .map_or::<&[Option<VMFuncRef>], _>(&[], |e| &**e);
680
681        if src.checked_add(len).is_none_or(|n| n as usize > elem.len())
682            || dst.checked_add(len).is_none_or(|m| m > table.size())
683        {
684            return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
685        }
686
687        for (dst, src) in (dst..dst + len).zip(src..src + len) {
688            table
689                .set(dst, TableElement::FuncRef(elem[src as usize]))
690                .expect("should never panic because we already did the bounds check above");
691        }
692
693        self.sync_fixed_funcref_table_by_index(table_index);
694
695        Ok(())
696    }
697
698    /// The `table.fill` operation: fills a portion of a table with a given value.
699    ///
700    /// # Errors
701    ///
702    /// Returns a `Trap` error when the range within the table is out of bounds
703    pub(crate) fn table_fill(
704        &mut self,
705        table_index: TableIndex,
706        start_index: u32,
707        item: TableElement,
708        len: u32,
709    ) -> Result<(), Trap> {
710        // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init
711
712        let table = self.get_table(table_index);
713        let table_size = table.size() as usize;
714
715        if start_index
716            .checked_add(len)
717            .is_none_or(|n| n as usize > table_size)
718        {
719            return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
720        }
721
722        for i in start_index..(start_index + len) {
723            table
724                .set(i, item.clone())
725                .expect("should never panic because we already did the bounds check above");
726        }
727
728        self.sync_fixed_funcref_table_by_index(table_index);
729
730        Ok(())
731    }
732
733    /// The `table.copy` operation.
734    pub(crate) fn table_copy(
735        &mut self,
736        dst_table_index: TableIndex,
737        src_table_index: TableIndex,
738        dst: u32,
739        src: u32,
740        len: u32,
741    ) -> Result<(), Trap> {
742        let result = if dst_table_index == src_table_index {
743            let table = self.get_table(dst_table_index);
744            table.copy_within(dst, src, len)
745        } else {
746            let dst_table = self.get_table_handle(dst_table_index);
747            let src_table = self.get_table_handle(src_table_index);
748            if dst_table == src_table {
749                unsafe {
750                    dst_table
751                        .get_mut(&mut *self.context)
752                        .copy_within(dst, src, len)
753                }
754            } else {
755                unsafe {
756                    dst_table.get_mut(&mut *self.context).copy(
757                        src_table.get(&*self.context),
758                        dst,
759                        src,
760                        len,
761                    )
762                }
763            }
764        };
765        result?;
766        self.sync_fixed_funcref_table_by_index(dst_table_index);
767
768        Ok(())
769    }
770
771    /// Drop an element.
772    pub(crate) fn elem_drop(&self, elem_index: ElemIndex) {
773        // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop
774
775        let mut passive_elements = self.passive_elements.borrow_mut();
776        passive_elements.remove(&elem_index);
777        // Note that we don't check that we actually removed an element because
778        // dropping a non-passive element is a no-op (not a trap).
779    }
780
781    /// Do a `memory.copy` for a locally defined memory.
782    ///
783    /// # Errors
784    ///
785    /// Returns a `Trap` error when the source or destination ranges are out of
786    /// bounds.
787    pub(crate) fn local_memory_copy(
788        &self,
789        memory_index: LocalMemoryIndex,
790        dst: u32,
791        src: u32,
792        len: u32,
793    ) -> Result<(), Trap> {
794        // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy
795
796        let memory = self.memory(memory_index);
797        // The following memory copy is not synchronized and is not atomic:
798        unsafe { memory_copy(&memory, dst, src, len) }
799    }
800
801    /// Perform a `memory.copy` on an imported memory.
802    pub(crate) fn imported_memory_copy(
803        &self,
804        memory_index: MemoryIndex,
805        dst: u32,
806        src: u32,
807        len: u32,
808    ) -> Result<(), Trap> {
809        let import = self.imported_memory(memory_index);
810        let memory = unsafe { import.definition.as_ref() };
811        // The following memory copy is not synchronized and is not atomic:
812        unsafe { memory_copy(memory, dst, src, len) }
813    }
814
815    /// Perform the `memory.fill` operation on a locally defined memory.
816    ///
817    /// # Errors
818    ///
819    /// Returns a `Trap` error if the memory range is out of bounds.
820    pub(crate) fn local_memory_fill(
821        &self,
822        memory_index: LocalMemoryIndex,
823        dst: u32,
824        val: u32,
825        len: u32,
826    ) -> Result<(), Trap> {
827        let memory = self.memory(memory_index);
828        // The following memory fill is not synchronized and is not atomic:
829        unsafe { memory_fill(&memory, dst, val, len) }
830    }
831
832    /// Perform the `memory.fill` operation on an imported memory.
833    ///
834    /// # Errors
835    ///
836    /// Returns a `Trap` error if the memory range is out of bounds.
837    pub(crate) fn imported_memory_fill(
838        &self,
839        memory_index: MemoryIndex,
840        dst: u32,
841        val: u32,
842        len: u32,
843    ) -> Result<(), Trap> {
844        let import = self.imported_memory(memory_index);
845        let memory = unsafe { import.definition.as_ref() };
846        // The following memory fill is not synchronized and is not atomic:
847        unsafe { memory_fill(memory, dst, val, len) }
848    }
849
850    /// Performs the `memory.init` operation.
851    ///
852    /// # Errors
853    ///
854    /// Returns a `Trap` error if the destination range is out of this module's
855    /// memory's bounds or if the source range is outside the data segment's
856    /// bounds.
857    pub(crate) fn memory_init(
858        &self,
859        memory_index: MemoryIndex,
860        data_index: DataIndex,
861        dst: u32,
862        src: u32,
863        len: u32,
864    ) -> Result<(), Trap> {
865        // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init
866
867        let memory = self.get_vmmemory(memory_index);
868        let passive_data = self.passive_data.borrow();
869        // A missing entry (never existed) or a dropped one (`None`) both behave
870        // as a zero-length segment, so an in-bounds `memory.init` of non-zero
871        // length traps below.
872        let data = passive_data
873            .get(&data_index)
874            .and_then(|d| d.as_deref())
875            .unwrap_or(&[]);
876
877        let current_length = unsafe { memory.vmmemory().as_ref().current_length };
878        if src.checked_add(len).is_none_or(|n| n as usize > data.len())
879            || dst
880                .checked_add(len)
881                .is_none_or(|m| usize::try_from(m).unwrap() > current_length)
882        {
883            return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
884        }
885        let src_slice = &data[src as usize..(src + len) as usize];
886        unsafe { memory.initialize_with_data(dst as usize, src_slice) }
887    }
888
889    /// Drop the given data segment, truncating its length to zero.
890    pub(crate) fn data_drop(&self, data_index: DataIndex) {
891        let mut passive_data = self.passive_data.borrow_mut();
892        // Release this instance's reference to the shared bytes and mark the
893        // segment unusable. Other instances (and the module) are unaffected.
894        if let Some(slot) = passive_data.get_mut(&data_index) {
895            *slot = None;
896        }
897    }
898
899    /// Get a table by index regardless of whether it is locally-defined or an
900    /// imported, foreign table.
901    pub(crate) fn get_table(&mut self, table_index: TableIndex) -> &mut VMTable {
902        if let Some(local_table_index) = self.module.local_table_index(table_index) {
903            self.get_local_table(local_table_index)
904        } else {
905            self.get_foreign_table(table_index)
906        }
907    }
908
909    /// Get a locally-defined table.
910    pub(crate) fn get_local_table(&mut self, index: LocalTableIndex) -> &mut VMTable {
911        let table = self.tables[index];
912        table.get_mut(self.context_mut())
913    }
914
915    /// Get an imported, foreign table.
916    pub(crate) fn get_foreign_table(&mut self, index: TableIndex) -> &mut VMTable {
917        let import = self.imported_table(index);
918        let table = import.handle;
919        table.get_mut(self.context_mut())
920    }
921
922    /// Get a table handle by index regardless of whether it is locally-defined
923    /// or an imported, foreign table.
924    pub(crate) fn get_table_handle(
925        &mut self,
926        table_index: TableIndex,
927    ) -> InternalStoreHandle<VMTable> {
928        if let Some(local_table_index) = self.module.local_table_index(table_index) {
929            self.tables[local_table_index]
930        } else {
931            self.imported_table(table_index).handle
932        }
933    }
934
935    /// # Safety
936    /// See [`LinearMemory::do_wait`].
937    unsafe fn memory_wait(
938        memory: &mut VMMemory,
939        dst: u32,
940        expected: ExpectedValue,
941        timeout: i64,
942    ) -> Result<u32, Trap> {
943        let timeout = if timeout < 0 {
944            None
945        } else {
946            Some(std::time::Duration::from_nanos(timeout as u64))
947        };
948        match unsafe { memory.do_wait(dst, expected, timeout) } {
949            Ok(count) => Ok(count),
950            Err(_err) => Err(Trap::lib(TrapCode::HostInterrupt)),
951        }
952    }
953
954    /// Perform an Atomic.Wait32
955    pub(crate) fn local_memory_wait32(
956        &mut self,
957        memory_index: LocalMemoryIndex,
958        dst: u32,
959        val: u32,
960        timeout: i64,
961    ) -> Result<u32, Trap> {
962        let memory = self.memory(memory_index);
963        //if ! memory.shared {
964        // We should trap according to spec, but official test rely on not trapping...
965        //}
966
967        // Do a fast-path check of the expected value, and also ensure proper alignment
968        let ret = unsafe { memory32_atomic_check32(&memory, dst, val) };
969
970        if let Ok(mut ret) = ret {
971            if ret == 0 {
972                let memory = self.get_local_vmmemory_mut(memory_index);
973                // Safety: we have already checked alignment and bounds in memory32_atomic_check32
974                ret = unsafe { Self::memory_wait(memory, dst, ExpectedValue::U32(val), timeout)? };
975            }
976            Ok(ret)
977        } else {
978            ret
979        }
980    }
981
982    /// Perform an Atomic.Wait32
983    pub(crate) fn imported_memory_wait32(
984        &mut self,
985        memory_index: MemoryIndex,
986        dst: u32,
987        val: u32,
988        timeout: i64,
989    ) -> Result<u32, Trap> {
990        let import = self.imported_memory(memory_index);
991        let memory = unsafe { import.definition.as_ref() };
992        //if ! memory.shared {
993        // We should trap according to spec, but official test rely on not trapping...
994        //}
995
996        // Do a fast-path check of the expected value, and also ensure proper alignment
997        let ret = unsafe { memory32_atomic_check32(memory, dst, val) };
998
999        if let Ok(mut ret) = ret {
1000            if ret == 0 {
1001                let memory = self.get_vmmemory_mut(memory_index);
1002                // Safety: we have already checked alignment and bounds in memory32_atomic_check32
1003                ret = unsafe { Self::memory_wait(memory, dst, ExpectedValue::U32(val), timeout)? };
1004            }
1005            Ok(ret)
1006        } else {
1007            ret
1008        }
1009    }
1010
1011    /// Perform an Atomic.Wait64
1012    pub(crate) fn local_memory_wait64(
1013        &mut self,
1014        memory_index: LocalMemoryIndex,
1015        dst: u32,
1016        val: u64,
1017        timeout: i64,
1018    ) -> Result<u32, Trap> {
1019        let memory = self.memory(memory_index);
1020        //if ! memory.shared {
1021        // We should trap according to spec, but official test rely on not trapping...
1022        //}
1023
1024        // Do a fast-path check of the expected value, and also ensure proper alignment
1025        let ret = unsafe { memory32_atomic_check64(&memory, dst, val) };
1026
1027        if let Ok(mut ret) = ret {
1028            if ret == 0 {
1029                let memory = self.get_local_vmmemory_mut(memory_index);
1030                // Safety: we have already checked alignment and bounds in memory32_atomic_check64
1031                ret = unsafe { Self::memory_wait(memory, dst, ExpectedValue::U64(val), timeout)? };
1032            }
1033            Ok(ret)
1034        } else {
1035            ret
1036        }
1037    }
1038
1039    /// Perform an Atomic.Wait64
1040    pub(crate) fn imported_memory_wait64(
1041        &mut self,
1042        memory_index: MemoryIndex,
1043        dst: u32,
1044        val: u64,
1045        timeout: i64,
1046    ) -> Result<u32, Trap> {
1047        let import = self.imported_memory(memory_index);
1048        let memory = unsafe { import.definition.as_ref() };
1049        //if ! memory.shared {
1050        // We should trap according to spec, but official test rely on not trapping...
1051        //}
1052
1053        // Do a fast-path check of the expected value, and also ensure proper alignment
1054        let ret = unsafe { memory32_atomic_check64(memory, dst, val) };
1055
1056        if let Ok(mut ret) = ret {
1057            if ret == 0 {
1058                let memory = self.get_vmmemory_mut(memory_index);
1059                // Safety: we have already checked alignment and bounds in memory32_atomic_check64
1060                ret = unsafe { Self::memory_wait(memory, dst, ExpectedValue::U64(val), timeout)? };
1061            }
1062            Ok(ret)
1063        } else {
1064            ret
1065        }
1066    }
1067
1068    /// Perform an Atomic.Notify
1069    pub(crate) fn local_memory_notify(
1070        &mut self,
1071        memory_index: LocalMemoryIndex,
1072        dst: u32,
1073        count: u32,
1074    ) -> Result<u32, Trap> {
1075        let memory = self.get_local_vmmemory_mut(memory_index);
1076        Ok(memory.do_notify(dst, count))
1077    }
1078
1079    /// Perform an Atomic.Notify
1080    pub(crate) fn imported_memory_notify(
1081        &mut self,
1082        memory_index: MemoryIndex,
1083        dst: u32,
1084        count: u32,
1085    ) -> Result<u32, Trap> {
1086        let memory = self.get_vmmemory_mut(memory_index);
1087        Ok(memory.do_notify(dst, count))
1088    }
1089}
1090
1091/// A handle holding an `Instance` of a WebAssembly module.
1092///
1093/// This is more or less a public facade of the private `Instance`,
1094/// providing useful higher-level API.
1095#[derive(Debug, Eq, PartialEq)]
1096pub struct VMInstance {
1097    /// The layout of `Instance` (which can vary).
1098    instance_layout: Layout,
1099
1100    /// The `Instance` itself.
1101    ///
1102    /// `Instance` must not be dropped manually by Rust, because it's
1103    /// allocated manually with `alloc` and a specific layout (Rust
1104    /// would be able to drop `Instance` itself but it will imply a
1105    /// memory leak because of `alloc`).
1106    ///
1107    /// No one in the code has a copy of the `Instance`'s
1108    /// pointer. `Self` is the only one.
1109    instance: NonNull<Instance>,
1110}
1111
1112/// VMInstance are created with an InstanceAllocator
1113/// and it will "consume" the memory
1114/// So the Drop here actually free it (else it would be leaked)
1115impl Drop for VMInstance {
1116    fn drop(&mut self) {
1117        let instance_ptr = self.instance.as_ptr();
1118
1119        unsafe {
1120            // Need to drop all the actual Instance members
1121            instance_ptr.drop_in_place();
1122            // And then free the memory allocated for the Instance itself
1123            std::alloc::dealloc(instance_ptr as *mut u8, self.instance_layout);
1124        }
1125    }
1126}
1127
1128impl VMInstance {
1129    /// Create a new `VMInstance` pointing at freshly allocated instance data.
1130    ///
1131    /// # Safety
1132    ///
1133    /// This method is not necessarily inherently unsafe to call, but in general
1134    /// the APIs of an `Instance` are quite unsafe and have not been really
1135    /// audited for safety that much. As a result the unsafety here on this
1136    /// method is a low-overhead way of saying “this is an extremely unsafe type
1137    /// to work with”.
1138    ///
1139    /// Extreme care must be taken when working with `VMInstance` and it's
1140    /// recommended to have relatively intimate knowledge of how it works
1141    /// internally if you'd like to do so. If possible it's recommended to use
1142    /// the `wasmer` crate API rather than this type since that is vetted for
1143    /// safety.
1144    ///
1145    /// However the following must be taken care of before calling this function:
1146    /// - The memory at `instance.tables_ptr()` must be initialized with data for
1147    ///   all the local tables.
1148    /// - The memory at `instance.memories_ptr()` must be initialized with data for
1149    ///   all the local memories.
1150    #[allow(clippy::too_many_arguments)]
1151    pub unsafe fn new(
1152        allocator: InstanceAllocator,
1153        module: Arc<ModuleInfo>,
1154        context: &mut StoreObjects,
1155        finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
1156        finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
1157        finished_memories: BoxedSlice<LocalMemoryIndex, InternalStoreHandle<VMMemory>>,
1158        finished_tables: BoxedSlice<LocalTableIndex, InternalStoreHandle<VMTable>>,
1159        finished_globals: BoxedSlice<LocalGlobalIndex, InternalStoreHandle<VMGlobal>>,
1160        tags: BoxedSlice<TagIndex, InternalStoreHandle<VMTag>>,
1161        imports: Imports,
1162        vmshared_signatures: BoxedSlice<SignatureIndex, VMSignatureHash>,
1163    ) -> Result<Self, Trap> {
1164        unsafe {
1165            let vmctx_tags = tags
1166                .values()
1167                .map(|m: &InternalStoreHandle<VMTag>| VMSharedTagIndex::new(m.index() as u32))
1168                .collect::<PrimaryMap<TagIndex, VMSharedTagIndex>>()
1169                .into_boxed_slice();
1170            // Share the module's passive data bytes via `Arc` (refcount bump)
1171            // rather than deep-copying them into every instance.
1172            let passive_data = RefCell::new(
1173                module
1174                    .passive_data
1175                    .iter()
1176                    .map(|(&idx, bytes)| (idx, Some(Arc::clone(bytes))))
1177                    .collect::<HashMap<_, _>>(),
1178            );
1179
1180            let handle = {
1181                let offsets = allocator.offsets().clone();
1182                // use dummy value to create an instance so we can get the vmctx pointer
1183                let funcrefs = PrimaryMap::new().into_boxed_slice();
1184                let imported_funcrefs = PrimaryMap::new().into_boxed_slice();
1185                // Create the `Instance`. The unique, the One.
1186                let instance = Instance {
1187                    module,
1188                    context,
1189                    offsets,
1190                    memories: finished_memories,
1191                    tables: finished_tables,
1192                    tags,
1193                    globals: finished_globals,
1194                    functions: finished_functions,
1195                    function_call_trampolines: finished_function_call_trampolines,
1196                    passive_elements: Default::default(),
1197                    passive_data,
1198                    funcrefs,
1199                    imported_funcrefs,
1200                    vmctx: VMContext {},
1201                };
1202
1203                let mut instance_handle = allocator.into_vminstance(instance);
1204
1205                // Set the funcrefs after we've built the instance
1206                {
1207                    let instance = instance_handle.instance_mut();
1208                    let vmctx_ptr = instance.vmctx_ptr();
1209                    (instance.funcrefs, instance.imported_funcrefs) = build_funcrefs(
1210                        &instance.module,
1211                        context,
1212                        &imports,
1213                        &instance.functions,
1214                        &vmshared_signatures,
1215                        &instance.function_call_trampolines,
1216                        vmctx_ptr,
1217                    );
1218                    for local_table_index in instance.tables.keys() {
1219                        instance.sync_fixed_funcref_table(local_table_index);
1220                    }
1221                }
1222
1223                instance_handle
1224            };
1225            let instance = handle.instance();
1226
1227            ptr::copy(
1228                vmctx_tags.values().as_slice().as_ptr(),
1229                instance.shared_tags_ptr(),
1230                vmctx_tags.len(),
1231            );
1232            ptr::copy(
1233                imports.functions.values().as_slice().as_ptr(),
1234                instance.imported_functions_ptr(),
1235                imports.functions.len(),
1236            );
1237            ptr::copy(
1238                imports.tables.values().as_slice().as_ptr(),
1239                instance.imported_tables_ptr(),
1240                imports.tables.len(),
1241            );
1242            ptr::copy(
1243                imports.memories.values().as_slice().as_ptr(),
1244                instance.imported_memories_ptr(),
1245                imports.memories.len(),
1246            );
1247            ptr::copy(
1248                imports.globals.values().as_slice().as_ptr(),
1249                instance.imported_globals_ptr(),
1250                imports.globals.len(),
1251            );
1252            // these should already be set, add asserts here? for:
1253            // - instance.tables_ptr() as *mut VMTableDefinition
1254            // - instance.memories_ptr() as *mut VMMemoryDefinition
1255            ptr::write(
1256                instance.builtin_functions_ptr(),
1257                VMBuiltinFunctionsArray::initialized(),
1258            );
1259
1260            // Perform infallible initialization in this constructor, while fallible
1261            // initialization is deferred to the `initialize` method.
1262            initialize_passive_elements(instance);
1263            initialize_globals(instance);
1264
1265            Ok(handle)
1266        }
1267    }
1268
1269    /// Return a reference to the contained `Instance`.
1270    pub(crate) fn instance(&self) -> &Instance {
1271        unsafe { self.instance.as_ref() }
1272    }
1273
1274    /// Return a mutable reference to the contained `Instance`.
1275    pub(crate) fn instance_mut(&mut self) -> &mut Instance {
1276        unsafe { self.instance.as_mut() }
1277    }
1278
1279    /// Finishes the instantiation process started by `Instance::new`.
1280    ///
1281    /// # Safety
1282    ///
1283    /// Only safe to call immediately after instantiation.
1284    pub unsafe fn finish_instantiation(
1285        &mut self,
1286        config: &VMConfig,
1287        trap_handler: Option<*const TrapHandlerFn<'static>>,
1288        data_initializers: &[DataInitializer<'_>],
1289    ) -> Result<(), Trap> {
1290        let instance = self.instance_mut();
1291
1292        // Apply the initializers.
1293        initialize_tables(instance)?;
1294        initialize_memories(instance, data_initializers)?;
1295
1296        // The WebAssembly spec specifies that the start function is
1297        // invoked automatically at instantiation time.
1298        instance.invoke_start_function(config, trap_handler)?;
1299        Ok(())
1300    }
1301
1302    /// Return a reference to the vmctx used by compiled wasm code.
1303    pub fn vmctx(&self) -> &VMContext {
1304        self.instance().vmctx()
1305    }
1306
1307    /// Return a raw pointer to the vmctx used by compiled wasm code.
1308    pub fn vmctx_ptr(&self) -> *mut VMContext {
1309        self.instance().vmctx_ptr()
1310    }
1311
1312    /// Return a reference to the `VMOffsets` to get offsets in the
1313    /// `Self::vmctx_ptr` region. Be careful when doing pointer
1314    /// arithmetic!
1315    pub fn vmoffsets(&self) -> &VMOffsets {
1316        self.instance().offsets()
1317    }
1318
1319    /// Return a reference-counting pointer to a module.
1320    pub fn module(&self) -> &Arc<ModuleInfo> {
1321        self.instance().module()
1322    }
1323
1324    /// Return a reference to a module.
1325    pub fn module_ref(&self) -> &ModuleInfo {
1326        self.instance().module_ref()
1327    }
1328
1329    /// Lookup an export with the given name.
1330    pub fn lookup(&mut self, field: &str) -> Option<VMExtern> {
1331        let export = *self.module_ref().exports.get(field)?;
1332
1333        Some(self.lookup_by_declaration(export))
1334    }
1335
1336    /// Lookup an export with the given export declaration.
1337    pub fn lookup_by_declaration(&mut self, export: ExportIndex) -> VMExtern {
1338        let instance = self.instance();
1339
1340        match export {
1341            ExportIndex::Function(index) => {
1342                let sig_index = &instance.module.functions[index];
1343                let handle = if let Some(def_index) = instance.module.local_func_index(index) {
1344                    // A VMFunction is lazily created only for functions that are
1345                    // exported.
1346                    let signature = instance.module.signatures[*sig_index].clone();
1347                    let vm_function = VMFunction {
1348                        anyfunc: MaybeInstanceOwned::Instance(NonNull::from(
1349                            &instance.funcrefs[def_index],
1350                        )),
1351                        signature,
1352                        // Any function received is already static at this point as:
1353                        // 1. All locally defined functions in the Wasm have a static signature.
1354                        // 2. All the imported functions are already static (because
1355                        //    they point to the trampolines rather than the dynamic addresses).
1356                        kind: VMFunctionKind::Static,
1357                        host_data: Box::new(()),
1358                    };
1359                    InternalStoreHandle::new(self.instance_mut().context_mut(), vm_function)
1360                } else {
1361                    let import = instance.imported_function(index);
1362                    import.handle
1363                };
1364
1365                VMExtern::Function(handle)
1366            }
1367            ExportIndex::Table(index) => {
1368                let handle = if let Some(def_index) = instance.module.local_table_index(index) {
1369                    instance.tables[def_index]
1370                } else {
1371                    let import = instance.imported_table(index);
1372                    import.handle
1373                };
1374                VMExtern::Table(handle)
1375            }
1376            ExportIndex::Memory(index) => {
1377                let handle = if let Some(def_index) = instance.module.local_memory_index(index) {
1378                    instance.memories[def_index]
1379                } else {
1380                    let import = instance.imported_memory(index);
1381                    import.handle
1382                };
1383                VMExtern::Memory(handle)
1384            }
1385            ExportIndex::Global(index) => {
1386                let handle = if let Some(def_index) = instance.module.local_global_index(index) {
1387                    instance.globals[def_index]
1388                } else {
1389                    let import = instance.imported_global(index);
1390                    import.handle
1391                };
1392                VMExtern::Global(handle)
1393            }
1394
1395            ExportIndex::Tag(index) => {
1396                let handle = instance.tags[index];
1397                VMExtern::Tag(handle)
1398            }
1399        }
1400    }
1401
1402    /// Return an iterator over the exports of this instance.
1403    ///
1404    /// Specifically, it provides access to the key-value pairs, where the keys
1405    /// are export names, and the values are export declarations which can be
1406    /// resolved `lookup_by_declaration`.
1407    pub fn exports(&self) -> indexmap::map::Iter<'_, String, ExportIndex> {
1408        self.module().exports.iter()
1409    }
1410
1411    /// Return the memory index for the given `VMMemoryDefinition` in this instance.
1412    pub fn memory_index(&self, memory: &VMMemoryDefinition) -> LocalMemoryIndex {
1413        self.instance().memory_index(memory)
1414    }
1415
1416    /// Grow memory in this instance by the specified amount of pages.
1417    ///
1418    /// Returns `None` if memory can't be grown by the specified amount
1419    /// of pages.
1420    pub fn memory_grow<IntoPages>(
1421        &mut self,
1422        memory_index: LocalMemoryIndex,
1423        delta: IntoPages,
1424    ) -> Result<Pages, MemoryError>
1425    where
1426        IntoPages: Into<Pages>,
1427    {
1428        self.instance_mut().memory_grow(memory_index, delta)
1429    }
1430
1431    /// Return the table index for the given `VMTableDefinition` in this instance.
1432    pub fn table_index(&self, table: &VMTableDefinition) -> LocalTableIndex {
1433        self.instance().table_index(table)
1434    }
1435
1436    /// Grow table in this instance by the specified amount of pages.
1437    ///
1438    /// Returns `None` if memory can't be grown by the specified amount
1439    /// of pages.
1440    pub fn table_grow(
1441        &mut self,
1442        table_index: LocalTableIndex,
1443        delta: u32,
1444        init_value: TableElement,
1445    ) -> Option<u32> {
1446        self.instance_mut()
1447            .table_grow(table_index, delta, init_value)
1448    }
1449
1450    /// Get table element reference.
1451    ///
1452    /// Returns `None` if index is out of bounds.
1453    pub fn table_get(&self, table_index: LocalTableIndex, index: u32) -> Option<TableElement> {
1454        self.instance().table_get(table_index, index)
1455    }
1456
1457    /// Set table element reference.
1458    ///
1459    /// Returns an error if the index is out of bounds
1460    pub fn table_set(
1461        &mut self,
1462        table_index: LocalTableIndex,
1463        index: u32,
1464        val: TableElement,
1465    ) -> Result<(), Trap> {
1466        self.instance_mut().table_set(table_index, index, val)
1467    }
1468
1469    /// Get a table defined locally within this module.
1470    pub fn get_local_table(&mut self, index: LocalTableIndex) -> &mut VMTable {
1471        self.instance_mut().get_local_table(index)
1472    }
1473}
1474
1475#[allow(clippy::mut_from_ref)]
1476#[allow(dead_code)]
1477/// Return a byte-slice view of a memory's data.
1478unsafe fn get_memory_slice<'instance>(
1479    init: &DataInitializer<'_>,
1480    instance: &'instance Instance,
1481) -> &'instance mut [u8] {
1482    unsafe {
1483        let memory = if let Some(local_memory_index) = instance
1484            .module
1485            .local_memory_index(init.location.memory_index)
1486        {
1487            instance.memory(local_memory_index)
1488        } else {
1489            let import = instance.imported_memory(init.location.memory_index);
1490            *import.definition.as_ref()
1491        };
1492        slice::from_raw_parts_mut(memory.base, memory.current_length)
1493    }
1494}
1495
1496fn get_global(index: GlobalIndex, instance: &Instance) -> RawValue {
1497    unsafe {
1498        if let Some(local_global_index) = instance.module.local_global_index(index) {
1499            instance.global(local_global_index).val
1500        } else {
1501            instance.imported_global(index).definition.as_ref().val
1502        }
1503    }
1504}
1505
1506enum EvaluatedInitExpr {
1507    I32(i32),
1508    I64(i64),
1509}
1510
1511fn eval_init_expr(expr: &InitExpr, instance: &Instance) -> EvaluatedInitExpr {
1512    if expr
1513        .ops()
1514        .first()
1515        .expect("missing expression")
1516        .is_32bit_expression()
1517    {
1518        let mut stack = Vec::with_capacity(expr.ops().len());
1519        for op in expr.ops() {
1520            match *op {
1521                InitExprOp::I32Const(value) => stack.push(value),
1522                InitExprOp::GlobalGetI32(global) => {
1523                    stack.push(unsafe { get_global(global, instance).i32 })
1524                }
1525                InitExprOp::I32Add => {
1526                    let rhs = stack.pop().expect("invalid init expr stack for i32.add");
1527                    let lhs = stack.pop().expect("invalid init expr stack for i32.add");
1528                    stack.push(lhs.wrapping_add(rhs));
1529                }
1530                InitExprOp::I32Sub => {
1531                    let rhs = stack.pop().expect("invalid init expr stack for i32.sub");
1532                    let lhs = stack.pop().expect("invalid init expr stack for i32.sub");
1533                    stack.push(lhs.wrapping_sub(rhs));
1534                }
1535                InitExprOp::I32Mul => {
1536                    let rhs = stack.pop().expect("invalid init expr stack for i32.mul");
1537                    let lhs = stack.pop().expect("invalid init expr stack for i32.mul");
1538                    stack.push(lhs.wrapping_mul(rhs));
1539                }
1540                _ => {
1541                    panic!("unexpected init expr statement: {op:?}");
1542                }
1543            }
1544        }
1545        EvaluatedInitExpr::I32(
1546            stack
1547                .into_iter()
1548                .exactly_one()
1549                .expect("invalid init expr stack shape"),
1550        )
1551    } else {
1552        let mut stack = Vec::with_capacity(expr.ops().len());
1553        for op in expr.ops() {
1554            match *op {
1555                InitExprOp::I64Const(value) => stack.push(value),
1556                InitExprOp::GlobalGetI64(global) => {
1557                    stack.push(unsafe { get_global(global, instance).i64 })
1558                }
1559                InitExprOp::I64Add => {
1560                    let rhs = stack.pop().expect("invalid init expr stack for i64.add");
1561                    let lhs = stack.pop().expect("invalid init expr stack for i64.add");
1562                    stack.push(lhs.wrapping_add(rhs));
1563                }
1564                InitExprOp::I64Sub => {
1565                    let rhs = stack.pop().expect("invalid init expr stack for i64.sub");
1566                    let lhs = stack.pop().expect("invalid init expr stack for i64.sub");
1567                    stack.push(lhs.wrapping_sub(rhs));
1568                }
1569                InitExprOp::I64Mul => {
1570                    let rhs = stack.pop().expect("invalid init expr stack for i64.mul");
1571                    let lhs = stack.pop().expect("invalid init expr stack for i64.mul");
1572                    stack.push(lhs.wrapping_mul(rhs));
1573                }
1574                _ => {
1575                    panic!("unexpected init expr statement: {op:?}");
1576                }
1577            }
1578        }
1579        EvaluatedInitExpr::I64(
1580            stack
1581                .into_iter()
1582                .exactly_one()
1583                .expect("invalid init expr stack shape"),
1584        )
1585    }
1586}
1587
1588/// Initialize the table memory from the provided initializers.
1589fn initialize_tables(instance: &mut Instance) -> Result<(), Trap> {
1590    let module = Arc::clone(&instance.module);
1591    for init in &module.table_initializers {
1592        let EvaluatedInitExpr::I32(start) = eval_init_expr(&init.offset_expr, instance) else {
1593            panic!("unexpected expression type, expected i32");
1594        };
1595        if start < 0 {
1596            return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
1597        }
1598        let start = start as usize;
1599        let table = instance.get_table_handle(init.table_index);
1600        let table = unsafe { table.get_mut(&mut *instance.context) };
1601
1602        if start
1603            .checked_add(init.elements.len())
1604            .is_none_or(|end| end > table.size() as usize)
1605        {
1606            return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
1607        }
1608
1609        if let wasmer_types::Type::FuncRef = table.ty().ty {
1610            for (i, func_idx) in init.elements.iter().enumerate() {
1611                let anyfunc = instance.func_ref(*func_idx);
1612                table
1613                    .set_with_construction(
1614                        u32::try_from(start + i).unwrap(),
1615                        TableElement::FuncRef(anyfunc),
1616                        true,
1617                    )
1618                    .unwrap();
1619            }
1620        } else {
1621            for i in 0..init.elements.len() {
1622                table
1623                    .set_with_construction(
1624                        u32::try_from(start + i).unwrap(),
1625                        TableElement::ExternRef(None),
1626                        true,
1627                    )
1628                    .unwrap();
1629            }
1630        }
1631
1632        instance.sync_fixed_funcref_table_by_index(init.table_index);
1633    }
1634
1635    Ok(())
1636}
1637
1638/// Initialize the `Instance::passive_elements` map by resolving the
1639/// `ModuleInfo::passive_elements`'s `FunctionIndex`s into `VMCallerCheckedAnyfunc`s for
1640/// this instance.
1641fn initialize_passive_elements(instance: &Instance) {
1642    let mut passive_elements = instance.passive_elements.borrow_mut();
1643    debug_assert!(
1644        passive_elements.is_empty(),
1645        "should only be called once, at initialization time"
1646    );
1647
1648    passive_elements.extend(instance.module.passive_elements.iter().filter_map(
1649        |(&idx, segments)| -> Option<(ElemIndex, Box<[Option<VMFuncRef>]>)> {
1650            if segments.is_empty() {
1651                None
1652            } else {
1653                Some((
1654                    idx,
1655                    segments
1656                        .iter()
1657                        .map(|s| instance.func_ref(*s))
1658                        .collect::<Box<[Option<VMFuncRef>]>>(),
1659                ))
1660            }
1661        },
1662    ));
1663}
1664
1665/// Initialize the table memory from the provided initializers.
1666fn initialize_memories(
1667    instance: &mut Instance,
1668    data_initializers: &[DataInitializer<'_>],
1669) -> Result<(), Trap> {
1670    for init in data_initializers {
1671        let memory = instance.get_vmmemory(init.location.memory_index);
1672
1673        let EvaluatedInitExpr::I32(start) = eval_init_expr(&init.location.offset_expr, instance)
1674        else {
1675            panic!("unexpected expression type, expected i32");
1676        };
1677        if start < 0 {
1678            return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
1679        }
1680        let start = start as usize;
1681        unsafe {
1682            let current_length = memory.vmmemory().as_ref().current_length;
1683            if start
1684                .checked_add(init.data.len())
1685                .is_none_or(|end| end > current_length)
1686            {
1687                return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
1688            }
1689            memory.initialize_with_data(start, init.data)?;
1690        }
1691    }
1692
1693    Ok(())
1694}
1695
1696fn initialize_globals(instance: &Instance) {
1697    let module = Arc::clone(&instance.module);
1698    for (index, initializer) in module.global_initializers.iter() {
1699        unsafe {
1700            let to = instance.global_ptr(index).as_ptr();
1701            match initializer {
1702                GlobalInit::I32Const(x) => (*to).val.i32 = *x,
1703                GlobalInit::I64Const(x) => (*to).val.i64 = *x,
1704                GlobalInit::F32Const(x) => (*to).val.f32 = *x,
1705                GlobalInit::F64Const(x) => (*to).val.f64 = *x,
1706                GlobalInit::V128Const(x) => (*to).val.bytes = *x.bytes(),
1707                GlobalInit::GetGlobal(x) => {
1708                    let from: VMGlobalDefinition =
1709                        if let Some(def_x) = module.local_global_index(*x) {
1710                            instance.global(def_x)
1711                        } else {
1712                            instance.imported_global(*x).definition.as_ref().clone()
1713                        };
1714                    *to = from;
1715                }
1716                GlobalInit::RefNullConst => (*to).val.funcref = 0,
1717                GlobalInit::RefFunc(func_idx) => {
1718                    let funcref = instance.func_ref(*func_idx).unwrap();
1719                    (*to).val = funcref.into_raw();
1720                }
1721                GlobalInit::Expr(expr) => match eval_init_expr(expr, instance) {
1722                    EvaluatedInitExpr::I32(value) => (*to).val.i32 = value,
1723                    EvaluatedInitExpr::I64(value) => (*to).val.i64 = value,
1724                },
1725            }
1726        }
1727    }
1728}
1729
1730fn anyfunc_from_funcref(funcref: Option<VMFuncRef>) -> VMCallerCheckedAnyfunc {
1731    match funcref {
1732        Some(funcref) => unsafe { *funcref.0.as_ptr() },
1733        None => VMCallerCheckedAnyfunc::null(),
1734    }
1735}
1736
1737/// Eagerly builds all the `VMFuncRef`s for imported and local functions so that all
1738/// future funcref operations are just looking up this data.
1739fn build_funcrefs(
1740    module_info: &ModuleInfo,
1741    ctx: &StoreObjects,
1742    imports: &Imports,
1743    finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
1744    vmshared_signatures: &BoxedSlice<SignatureIndex, VMSignatureHash>,
1745    function_call_trampolines: &BoxedSlice<SignatureIndex, VMTrampoline>,
1746    vmctx_ptr: *mut VMContext,
1747) -> (
1748    BoxedSlice<LocalFunctionIndex, VMCallerCheckedAnyfunc>,
1749    BoxedSlice<FunctionIndex, NonNull<VMCallerCheckedAnyfunc>>,
1750) {
1751    let mut func_refs =
1752        PrimaryMap::with_capacity(module_info.functions.len() - module_info.num_imported_functions);
1753    let mut imported_func_refs = PrimaryMap::with_capacity(module_info.num_imported_functions);
1754
1755    // do imported functions
1756    for import in imports.functions.values() {
1757        imported_func_refs.push(import.handle.get(ctx).anyfunc.as_ptr());
1758    }
1759
1760    // do local functions
1761    for (local_index, func_ptr) in finished_functions.iter() {
1762        let index = module_info.func_index(local_index);
1763        let sig_index = module_info.functions[index];
1764        let type_signature_hash = vmshared_signatures[sig_index];
1765        let call_trampoline = function_call_trampolines[sig_index];
1766        let anyfunc = VMCallerCheckedAnyfunc {
1767            func_ptr: func_ptr.0,
1768            type_signature_hash,
1769            vmctx: VMFunctionContext { vmctx: vmctx_ptr },
1770            call_trampoline,
1771        };
1772        func_refs.push(anyfunc);
1773    }
1774    (
1775        func_refs.into_boxed_slice(),
1776        imported_func_refs.into_boxed_slice(),
1777    )
1778}