Skip to main content

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