near_vm_vm/instance/
mod.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/2.3.0/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//! `InstanceRef` is a wrapper around `Instance` that manages
7//! how it is allocated and deallocated. An `InstanceHandle` is a
8//! wrapper around an `InstanceRef`.
9
10mod allocator;
11mod r#ref;
12
13pub use allocator::InstanceAllocator;
14pub use r#ref::{InstanceRef, WeakOrStrongInstanceRef};
15
16use crate::func_data_registry::VMFuncRef;
17use crate::global::Global;
18use crate::imports::Imports;
19use crate::memory::{LinearMemory, MemoryError};
20use crate::sig_registry::VMSharedSignatureIndex;
21use crate::table::{Table, TableElement};
22use crate::trap::traphandlers::get_trap_handler;
23use crate::trap::{Trap, TrapCode, catch_traps};
24use crate::vmcontext::{
25    VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody,
26    VMFunctionEnvironment, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport,
27    VMLocalFunction, VMMemoryDefinition, VMMemoryImport, VMTableDefinition, VMTableImport,
28};
29use crate::{Artifact, VMOffsets, VMTrampoline, near_vm_call_trampoline};
30use crate::{VMExtern, VMFunction, VMGlobal};
31use memoffset::offset_of;
32use more_asserts::assert_lt;
33use near_vm_types::entity::{BoxedSlice, EntityRef, PrimaryMap, packed_option::ReservedValue};
34use near_vm_types::{
35    DataIndex, DataInitializer, ElemIndex, ExportIndex, FastGasCounter, FunctionIndex, GlobalIndex,
36    GlobalInit, InstanceConfig, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
37    OwnedTableInitializer, Pages, TableIndex,
38};
39use std::any::Any;
40use std::cell::RefCell;
41use std::collections::BTreeMap;
42use std::convert::TryFrom;
43use std::ffi;
44use std::fmt;
45use std::mem;
46use std::ptr::{self, NonNull};
47use std::slice;
48use std::sync::Arc;
49
50/// The function pointer to call with data and an [`Instance`] pointer to
51/// finish initializing the host env.
52pub type ImportInitializerFuncPtr<ResultErr = *mut ffi::c_void> =
53    fn(*mut ffi::c_void, *const ffi::c_void) -> Result<(), ResultErr>;
54
55/// A WebAssembly instance.
56///
57/// The type is dynamically-sized. Indeed, the `vmctx` field can
58/// contain various data. That's why the type has a C representation
59/// to ensure that the `vmctx` field is last. See the documentation of
60/// the `vmctx` field to learn more.
61#[repr(C)]
62pub struct Instance {
63    pub(crate) artifact: Arc<dyn Artifact>,
64
65    /// External configuration for instance.
66    config: InstanceConfig,
67
68    /// WebAssembly linear memory data.
69    memories: BoxedSlice<LocalMemoryIndex, Arc<LinearMemory>>,
70
71    /// Table data...
72    tables: BoxedSlice<LocalTableIndex, Arc<dyn Table>>,
73
74    /// WebAssembly global data.
75    globals: BoxedSlice<LocalGlobalIndex, Arc<Global>>,
76
77    /// Passive elements in this instantiation. As `elem.drop`s happen, these
78    /// entries get removed.
79    passive_elements: RefCell<BTreeMap<ElemIndex, Box<[VMFuncRef]>>>,
80
81    /// Passive data segments from our module. As `data.drop`s happen, entries
82    /// get removed. A missing entry is considered equivalent to an empty slice.
83    passive_data: RefCell<BTreeMap<DataIndex, Arc<[u8]>>>,
84
85    /// Mapping of function indices to their func ref backing data. `VMFuncRef`s
86    /// will point to elements here for functions defined or imported by this
87    /// instance.
88    funcrefs: BoxedSlice<FunctionIndex, VMCallerCheckedAnyfunc>,
89
90    /// Hosts can store arbitrary per-instance information here.
91    host_state: Box<dyn Any>,
92
93    /// Functions to operate on host environments in the imports
94    /// and pointers to the environments.
95    ///
96    /// TODO: Be sure to test with serialize/deserialize and imported
97    /// functions from other Wasm modules.
98    imported_function_envs: BoxedSlice<FunctionIndex, ImportFunctionEnv>,
99
100    /// Additional context used by compiled WebAssembly code. This
101    /// field is last, and represents a dynamically-sized array that
102    /// extends beyond the nominal end of the struct (similar to a
103    /// flexible array member).
104    vmctx: VMContext,
105}
106
107/// A collection of data about host envs used by imported functions.
108#[derive(Debug)]
109pub enum ImportFunctionEnv {
110    /// The `vmctx` pointer does not refer to a host env, there is no
111    /// metadata about it.
112    NoEnv,
113    /// We're dealing with a user-defined host env.
114    ///
115    /// This host env may be either unwrapped (the user-supplied host env
116    /// directly) or wrapped. i.e. in the case of Dynamic functions, we
117    /// store our own extra data along with the user supplied env,
118    /// thus the `env` pointer here points to the outermost type.
119    Env {
120        /// The function environment. This is not always the user-supplied
121        /// env.
122        env: *mut ffi::c_void,
123
124        /// A clone function for duplicating the env.
125        clone: fn(*mut ffi::c_void) -> *mut ffi::c_void,
126        /// This field is not always present. When it is present, it
127        /// should be set to `None` after use to prevent double
128        /// initialization.
129        initializer: Option<ImportInitializerFuncPtr>,
130        /// The destructor to clean up the type in `env`.
131        ///
132        /// # Safety
133        /// - This function must be called ina synchronized way. For
134        ///   example, in the `Drop` implementation of this type.
135        destructor: unsafe fn(*mut ffi::c_void),
136    },
137}
138
139impl Clone for ImportFunctionEnv {
140    fn clone(&self) -> Self {
141        match &self {
142            Self::NoEnv => Self::NoEnv,
143            Self::Env { env, clone, destructor, initializer } => {
144                let new_env = (*clone)(*env);
145                Self::Env {
146                    env: new_env,
147                    clone: *clone,
148                    destructor: *destructor,
149                    initializer: *initializer,
150                }
151            }
152        }
153    }
154}
155
156impl Drop for ImportFunctionEnv {
157    fn drop(&mut self) {
158        match self {
159            Self::Env { env, destructor, .. } => {
160                // # Safety
161                // - This is correct because we know no other references
162                //   to this data can exist if we're dropping it.
163                unsafe {
164                    (destructor)(*env);
165                }
166            }
167            Self::NoEnv => (),
168        }
169    }
170}
171
172impl fmt::Debug for Instance {
173    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
174        formatter.debug_struct("Instance").finish()
175    }
176}
177
178#[allow(clippy::cast_ptr_alignment)]
179impl Instance {
180    /// Helper function to access various locations offset from our `*mut
181    /// VMContext` object.
182    unsafe fn vmctx_plus_offset<T>(&self, offset: u32) -> *mut T {
183        unsafe { (self.vmctx_ptr() as *mut u8).add(usize::try_from(offset).unwrap()).cast() }
184    }
185
186    /// Offsets in the `vmctx` region.
187    fn offsets(&self) -> &VMOffsets {
188        self.artifact.offsets()
189    }
190
191    /// Return a pointer to the `VMSharedSignatureIndex`s.
192    fn signature_ids_ptr(&self) -> *mut VMSharedSignatureIndex {
193        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_signature_ids_begin()) }
194    }
195
196    /// Return the indexed `VMFunctionImport`.
197    fn imported_function(&self, index: FunctionIndex) -> &VMFunctionImport {
198        let index = usize::try_from(index.as_u32()).unwrap();
199        unsafe { &*self.imported_functions_ptr().add(index) }
200    }
201
202    /// Return a pointer to the `VMFunctionImport`s.
203    fn imported_functions_ptr(&self) -> *mut VMFunctionImport {
204        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_imported_functions_begin()) }
205    }
206
207    /// Return the index `VMTableImport`.
208    fn imported_table(&self, index: TableIndex) -> &VMTableImport {
209        let index = usize::try_from(index.as_u32()).unwrap();
210        unsafe { &*self.imported_tables_ptr().add(index) }
211    }
212
213    /// Return a pointer to the `VMTableImports`s.
214    fn imported_tables_ptr(&self) -> *mut VMTableImport {
215        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_imported_tables_begin()) }
216    }
217
218    /// Return the indexed `VMMemoryImport`.
219    fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport {
220        let index = usize::try_from(index.as_u32()).unwrap();
221        let addr = unsafe { self.imported_memories_ptr().add(index) };
222        let align = std::mem::align_of::<VMMemoryImport>();
223        debug_assert!(
224            addr as usize % align == 0,
225            "VMMemoryImport addr is not aligned to {align}: {addr:p}"
226        );
227        unsafe { &*addr }
228    }
229
230    /// Return a pointer to the `VMMemoryImport`s.
231    fn imported_memories_ptr(&self) -> *mut VMMemoryImport {
232        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_imported_memories_begin()) }
233    }
234
235    /// Return the indexed `VMGlobalImport`.
236    fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport {
237        let index = usize::try_from(index.as_u32()).unwrap();
238        unsafe { &*self.imported_globals_ptr().add(index) }
239    }
240
241    /// Return a pointer to the `VMGlobalImport`s.
242    fn imported_globals_ptr(&self) -> *mut VMGlobalImport {
243        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_imported_globals_begin()) }
244    }
245
246    /// Return the indexed `VMTableDefinition`.
247    #[allow(unused)]
248    fn table(&self, index: LocalTableIndex) -> VMTableDefinition {
249        unsafe { *self.table_ptr(index).as_ref() }
250    }
251
252    /// Updates the value for a defined table to `VMTableDefinition`.
253    #[allow(unused)]
254    fn set_table(&self, index: LocalTableIndex, table: &VMTableDefinition) {
255        unsafe {
256            *self.table_ptr(index).as_ptr() = *table;
257        }
258    }
259
260    /// Return the indexed `VMTableDefinition`.
261    fn table_ptr(&self, index: LocalTableIndex) -> NonNull<VMTableDefinition> {
262        let index = usize::try_from(index.as_u32()).unwrap();
263        NonNull::new(unsafe { self.tables_ptr().add(index) }).unwrap()
264    }
265
266    /// Return a pointer to the `VMTableDefinition`s.
267    fn tables_ptr(&self) -> *mut VMTableDefinition {
268        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_tables_begin()) }
269    }
270
271    /// Return the indexed `VMMemoryDefinition`.
272    fn memory_definition(&self, index: MemoryIndex) -> &VMMemoryDefinition {
273        match self.artifact.import_counts().local_memory_index(index) {
274            Ok(local) => unsafe { self.memory_ptr(local).as_ref() },
275            Err(import) => unsafe { &self.imported_memory(import).from.vmmemory().as_ref() },
276        }
277    }
278
279    #[allow(dead_code)]
280    /// Set the indexed memory to `VMMemoryDefinition`.
281    fn set_memory(&self, index: LocalMemoryIndex, mem: &VMMemoryDefinition) {
282        unsafe {
283            *self.memory_ptr(index).as_ptr() = *mem;
284        }
285    }
286
287    /// Return the indexed `VMMemoryDefinition`.
288    fn memory_ptr(&self, index: LocalMemoryIndex) -> NonNull<VMMemoryDefinition> {
289        let index = usize::try_from(index.as_u32()).unwrap();
290        NonNull::new(unsafe { self.memories_ptr().add(index) }).unwrap()
291    }
292
293    /// Return a pointer to the `VMMemoryDefinition`s.
294    fn memories_ptr(&self) -> *mut VMMemoryDefinition {
295        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_memories_begin()) }
296    }
297
298    /// Return the indexed `VMGlobalDefinition`.
299    fn global(&self, index: GlobalIndex) -> &VMGlobalDefinition {
300        match self.artifact.import_counts().local_global_index(index) {
301            Ok(local) => unsafe { self.global_ptr(local).as_ref() },
302            Err(import) => unsafe { self.imported_global(import).definition.as_ref() },
303        }
304    }
305
306    /// Set the indexed global to `VMGlobalDefinition`.
307    #[allow(dead_code)]
308    fn set_global(&self, index: LocalGlobalIndex, global: &VMGlobalDefinition) {
309        unsafe {
310            *self.global_ptr(index).as_ptr() = global.clone();
311        }
312    }
313
314    /// Return the indexed `VMGlobalDefinition`.
315    fn global_ptr(&self, index: LocalGlobalIndex) -> NonNull<VMGlobalDefinition> {
316        let index = usize::try_from(index.as_u32()).unwrap();
317        // TODO:
318        NonNull::new(unsafe { *self.globals_ptr().add(index) }).unwrap()
319    }
320
321    /// Return a pointer to the `VMGlobalDefinition`s.
322    fn globals_ptr(&self) -> *mut *mut VMGlobalDefinition {
323        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_globals_begin()) }
324    }
325
326    /// Return a pointer to the `VMBuiltinFunctionsArray`.
327    fn builtin_functions_ptr(&self) -> *mut VMBuiltinFunctionsArray {
328        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_builtin_functions_begin()) }
329    }
330
331    /// Return a reference to the vmctx used by compiled wasm code.
332    fn vmctx(&self) -> &VMContext {
333        &self.vmctx
334    }
335
336    /// Return a raw pointer to the vmctx used by compiled wasm code.
337    fn vmctx_ptr(&self) -> *mut VMContext {
338        self.vmctx() as *const VMContext as *mut VMContext
339    }
340
341    /// Return a reference to the custom state attached to this instance.
342    #[inline]
343    pub fn host_state(&self) -> &dyn Any {
344        &*self.host_state
345    }
346
347    /// Return a pointer to the trap catcher.
348    fn trap_catcher_ptr(&self) -> *mut *const u8 {
349        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_trap_handler()) }
350    }
351
352    /// Return a pointer to the gas limiter.
353    pub fn gas_counter_ptr(&self) -> *mut *const FastGasCounter {
354        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_gas_limiter_pointer()) }
355    }
356
357    /// Return a pointer to initial stack limit.
358    pub fn stack_limit_initial_ptr(&self) -> *mut u32 {
359        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_stack_limit_initial_begin()) }
360    }
361
362    /// Return a pointer to current stack limit.
363    pub fn stack_limit_ptr(&self) -> *mut u32 {
364        unsafe { self.vmctx_plus_offset(self.offsets().vmctx_stack_limit_begin()) }
365    }
366
367    /// Invoke the WebAssembly start function of the instance, if one is present.
368    fn invoke_start_function(&self) -> Result<(), Trap> {
369        let start_index = match self.artifact.start_function() {
370            Some(idx) => idx,
371            None => return Ok(()),
372        };
373        let start_funcref = self.funcrefs[start_index];
374        // Make the call.
375        self.reset_stack_meter();
376        let result = unsafe {
377            catch_traps(|| {
378                mem::transmute::<*const VMFunctionBody, unsafe extern "C" fn(VMFunctionEnvironment)>(
379                    start_funcref.func_ptr,
380                )(start_funcref.vmctx)
381            })
382        };
383        result
384    }
385
386    pub fn reset_stack_meter(&self) {
387        unsafe {
388            *(self.stack_limit_ptr()) = *(self.stack_limit_initial_ptr());
389        }
390    }
391
392    /// Return the offset from the vmctx pointer to its containing `Instance`.
393    #[inline]
394    pub(crate) fn vmctx_offset() -> isize {
395        offset_of!(Self, vmctx) as isize
396    }
397
398    /// Return the table index for the given `VMTableDefinition`.
399    pub(crate) fn table_index(&self, table: &VMTableDefinition) -> LocalTableIndex {
400        let begin: *const VMTableDefinition = self.tables_ptr() as *const _;
401        let end: *const VMTableDefinition = table;
402        // TODO: Use `offset_from` once it stabilizes.
403        let index = LocalTableIndex::new(
404            (end as usize - begin as usize) / mem::size_of::<VMTableDefinition>(),
405        );
406        assert_lt!(index.index(), self.tables.len());
407        index
408    }
409
410    /// Return the memory index for the given `VMMemoryDefinition`.
411    pub(crate) fn memory_index(&self, memory: &VMMemoryDefinition) -> LocalMemoryIndex {
412        let begin: *const VMMemoryDefinition = self.memories_ptr() as *const _;
413        let end: *const VMMemoryDefinition = memory;
414        // TODO: Use `offset_from` once it stabilizes.
415        let index = LocalMemoryIndex::new(
416            (end as usize - begin as usize) / mem::size_of::<VMMemoryDefinition>(),
417        );
418        assert_lt!(index.index(), self.memories.len());
419        index
420    }
421
422    /// Grow memory by the specified amount of pages.
423    ///
424    /// Returns `None` if memory can't be grown by the specified amount
425    /// of pages.
426    pub(crate) fn memory_grow<IntoPages>(
427        &self,
428        memory_index: LocalMemoryIndex,
429        delta: IntoPages,
430    ) -> Result<Pages, MemoryError>
431    where
432        IntoPages: Into<Pages>,
433    {
434        let mem = self
435            .memories
436            .get(memory_index)
437            .unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()));
438        mem.grow(delta.into())
439    }
440
441    /// Grow imported memory by the specified amount of pages.
442    ///
443    /// Returns `None` if memory can't be grown by the specified amount
444    /// of pages.
445    ///
446    /// # Safety
447    /// This and `imported_memory_size` are currently unsafe because they
448    /// dereference the memory import's pointers.
449    pub(crate) unsafe fn imported_memory_grow<IntoPages>(
450        &self,
451        memory_index: MemoryIndex,
452        delta: IntoPages,
453    ) -> Result<Pages, MemoryError>
454    where
455        IntoPages: Into<Pages>,
456    {
457        let import = self.imported_memory(memory_index);
458        import.from.grow(delta.into())
459    }
460
461    /// Returns the number of allocated wasm pages.
462    pub(crate) fn memory_size(&self, memory_index: LocalMemoryIndex) -> Pages {
463        self.memories
464            .get(memory_index)
465            .unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
466            .size()
467    }
468
469    /// Returns the number of allocated wasm pages in an imported memory.
470    ///
471    /// # Safety
472    /// This and `imported_memory_grow` are currently unsafe because they
473    /// dereference the memory import's pointers.
474    pub(crate) unsafe fn imported_memory_size(&self, memory_index: MemoryIndex) -> Pages {
475        self.imported_memory(memory_index).from.size()
476    }
477
478    /// Returns the number of elements in a given table.
479    pub(crate) fn table_size(&self, table_index: LocalTableIndex) -> u32 {
480        self.tables[table_index].size()
481    }
482
483    /// Returns the number of elements in a given imported table.
484    ///
485    /// # Safety
486    /// `table_index` must be a valid, imported table index.
487    pub(crate) unsafe fn imported_table_size(&self, table_index: TableIndex) -> u32 {
488        self.imported_table(table_index).from.size()
489    }
490
491    /// Grow table by the specified amount of elements.
492    ///
493    /// Returns `None` if table can't be grown by the specified amount
494    /// of elements.
495    pub(crate) fn table_grow(
496        &self,
497        table_index: LocalTableIndex,
498        delta: u32,
499        init_value: TableElement,
500    ) -> Option<u32> {
501        let result = self
502            .tables
503            .get(table_index)
504            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
505            .grow(delta, init_value);
506
507        result
508    }
509
510    /// Grow table by the specified amount of elements.
511    ///
512    /// # Safety
513    /// `table_index` must be a valid, imported table index.
514    pub(crate) unsafe fn imported_table_grow(
515        &self,
516        table_index: TableIndex,
517        delta: u32,
518        init_value: TableElement,
519    ) -> Option<u32> {
520        let import = self.imported_table(table_index);
521        import.from.grow(delta, init_value)
522    }
523
524    /// Get table element by index.
525    pub(crate) fn table_get(
526        &self,
527        table_index: LocalTableIndex,
528        index: u32,
529    ) -> Option<TableElement> {
530        self.tables
531            .get(table_index)
532            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
533            .get(index)
534    }
535
536    /// Returns the element at the given index.
537    ///
538    /// # Safety
539    /// `table_index` must be a valid, imported table index.
540    pub(crate) unsafe fn imported_table_get(
541        &self,
542        table_index: TableIndex,
543        index: u32,
544    ) -> Option<TableElement> {
545        let import = self.imported_table(table_index);
546        import.from.get(index)
547    }
548
549    /// Set table element by index.
550    pub(crate) fn table_set(
551        &self,
552        table_index: LocalTableIndex,
553        index: u32,
554        val: TableElement,
555    ) -> Result<(), Trap> {
556        self.tables
557            .get(table_index)
558            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
559            .set(index, val)
560    }
561
562    /// Set table element by index for an imported table.
563    ///
564    /// # Safety
565    /// `table_index` must be a valid, imported table index.
566    pub(crate) unsafe fn imported_table_set(
567        &self,
568        table_index: TableIndex,
569        index: u32,
570        val: TableElement,
571    ) -> Result<(), Trap> {
572        let import = self.imported_table(table_index);
573        import.from.set(index, val)
574    }
575
576    pub(crate) fn func_ref(&self, function_index: FunctionIndex) -> Option<VMFuncRef> {
577        Some(self.get_vm_funcref(function_index))
578    }
579
580    /// Get a `VMFuncRef` for the given `FunctionIndex`.
581    fn get_vm_funcref(&self, index: FunctionIndex) -> VMFuncRef {
582        if index == FunctionIndex::reserved_value() {
583            return VMFuncRef::null();
584        }
585        VMFuncRef(&self.funcrefs[index])
586    }
587
588    /// The `table.init` operation: initializes a portion of a table with a
589    /// passive element.
590    ///
591    /// # Errors
592    ///
593    /// Returns a `Trap` error when the range within the table is out of bounds
594    /// or the range within the passive element is out of bounds.
595    pub(crate) fn table_init(
596        &self,
597        table_index: TableIndex,
598        elem_index: ElemIndex,
599        dst: u32,
600        src: u32,
601        len: u32,
602    ) -> Result<(), Trap> {
603        // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init
604
605        let table = self.get_table(table_index);
606        let passive_elements = self.passive_elements.borrow();
607        let elem = passive_elements.get(&elem_index).map_or::<&[VMFuncRef], _>(&[], |e| &**e);
608
609        if src.checked_add(len).map_or(true, |n| n as usize > elem.len())
610            || dst.checked_add(len).map_or(true, |m| m > table.size())
611        {
612            return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
613        }
614
615        for (dst, src) in (dst..dst + len).zip(src..src + len) {
616            table
617                .set(dst, TableElement::FuncRef(elem[src as usize]))
618                .expect("should never panic because we already did the bounds check above");
619        }
620
621        Ok(())
622    }
623
624    /// The `table.fill` operation: fills a portion of a table with a given value.
625    ///
626    /// # Errors
627    ///
628    /// Returns a `Trap` error when the range within the table is out of bounds
629    pub(crate) fn table_fill(
630        &self,
631        table_index: TableIndex,
632        start_index: u32,
633        item: TableElement,
634        len: u32,
635    ) -> Result<(), Trap> {
636        // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init
637
638        let table = self.get_table(table_index);
639        let table_size = table.size() as usize;
640
641        if start_index.checked_add(len).map_or(true, |n| n as usize > table_size) {
642            return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
643        }
644
645        for i in start_index..(start_index + len) {
646            table
647                .set(i, item.clone())
648                .expect("should never panic because we already did the bounds check above");
649        }
650
651        Ok(())
652    }
653
654    /// Drop an element.
655    pub(crate) fn elem_drop(&self, elem_index: ElemIndex) {
656        // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop
657
658        let mut passive_elements = self.passive_elements.borrow_mut();
659        passive_elements.remove(&elem_index);
660        // Note that we don't check that we actually removed an element because
661        // dropping a non-passive element is a no-op (not a trap).
662    }
663
664    /// Do a `memory.copy` for a locally defined memory.
665    ///
666    /// # Errors
667    ///
668    /// Returns a `Trap` error when the source or destination ranges are out of
669    /// bounds.
670    pub(crate) fn local_memory_copy(
671        &self,
672        memory_index: LocalMemoryIndex,
673        dst: u32,
674        src: u32,
675        len: u32,
676    ) -> Result<(), Trap> {
677        // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy
678        let memory = unsafe { self.memory_ptr(memory_index).as_ref() };
679        // The following memory copy is not synchronized and is not atomic:
680        unsafe { memory.memory_copy(dst, src, len) }
681    }
682
683    /// Perform a `memory.copy` on an imported memory.
684    pub(crate) fn imported_memory_copy(
685        &self,
686        memory_index: MemoryIndex,
687        dst: u32,
688        src: u32,
689        len: u32,
690    ) -> Result<(), Trap> {
691        let import = self.imported_memory(memory_index);
692        // The following memory copy is not synchronized and is not atomic:
693        unsafe { import.from.vmmemory().as_ref().memory_copy(dst, src, len) }
694    }
695
696    /// Perform the `memory.fill` operation on a locally defined memory.
697    ///
698    /// # Errors
699    ///
700    /// Returns a `Trap` error if the memory range is out of bounds.
701    pub(crate) fn local_memory_fill(
702        &self,
703        memory_index: LocalMemoryIndex,
704        dst: u32,
705        val: u32,
706        len: u32,
707    ) -> Result<(), Trap> {
708        let memory = unsafe { self.memory_ptr(memory_index).as_ref() };
709        // The following memory fill is not synchronized and is not atomic:
710        unsafe { memory.memory_fill(dst, val, len) }
711    }
712
713    /// Perform the `memory.fill` operation on an imported memory.
714    ///
715    /// # Errors
716    ///
717    /// Returns a `Trap` error if the memory range is out of bounds.
718    pub(crate) fn imported_memory_fill(
719        &self,
720        memory_index: MemoryIndex,
721        dst: u32,
722        val: u32,
723        len: u32,
724    ) -> Result<(), Trap> {
725        let import = self.imported_memory(memory_index);
726        // The following memory fill is not synchronized and is not atomic:
727        unsafe { import.from.vmmemory().as_ref().memory_fill(dst, val, len) }
728    }
729
730    /// Performs the `memory.init` operation.
731    ///
732    /// # Errors
733    ///
734    /// Returns a `Trap` error if the destination range is out of this module's
735    /// memory's bounds or if the source range is outside the data segment's
736    /// bounds.
737    pub(crate) fn memory_init(
738        &self,
739        memory_index: MemoryIndex,
740        data_index: DataIndex,
741        dst: u32,
742        src: u32,
743        len: u32,
744    ) -> Result<(), Trap> {
745        // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init
746
747        let memory = self.memory_definition(memory_index);
748        let passive_data = self.passive_data.borrow();
749        let data = passive_data.get(&data_index).map_or(&[][..], |d| &**d);
750
751        let oob_access = src.checked_add(len).map_or(true, |n| n as usize > data.len())
752            || dst
753                .checked_add(len)
754                .map_or(true, |m| usize::try_from(m).unwrap() > memory.current_length);
755
756        if oob_access {
757            return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
758        }
759        let src_slice = &data[src as usize..(src + len) as usize];
760        unsafe {
761            let dst_start = memory.base.add(dst as usize);
762            let dst_slice = slice::from_raw_parts_mut(dst_start, len as usize);
763            dst_slice.copy_from_slice(src_slice);
764        }
765        Ok(())
766    }
767
768    /// Drop the given data segment, truncating its length to zero.
769    pub(crate) fn data_drop(&self, data_index: DataIndex) {
770        let mut passive_data = self.passive_data.borrow_mut();
771        passive_data.remove(&data_index);
772    }
773
774    /// Get a table by index regardless of whether it is locally-defined or an
775    /// imported, foreign table.
776    pub(crate) fn get_table(&self, table_index: TableIndex) -> &dyn Table {
777        match self.artifact.import_counts().local_table_index(table_index) {
778            Ok(local) => self.get_local_table(local),
779            Err(import) => self.get_foreign_table(import),
780        }
781    }
782
783    /// Get a locally-defined table.
784    pub(crate) fn get_local_table(&self, index: LocalTableIndex) -> &dyn Table {
785        self.tables[index].as_ref()
786    }
787
788    /// Get an imported, foreign table.
789    pub(crate) fn get_foreign_table(&self, index: TableIndex) -> &dyn Table {
790        let import = self.imported_table(index);
791        &*import.from
792    }
793}
794
795/// A handle holding an `InstanceRef`, which holds an `Instance`
796/// of a WebAssembly module.
797///
798/// This is more or less a public facade of the private `Instance`,
799/// providing useful higher-level API.
800#[derive(Debug, PartialEq)]
801pub struct InstanceHandle {
802    /// The [`InstanceRef`]. See its documentation to learn more.
803    instance: InstanceRef,
804}
805
806impl InstanceHandle {
807    /// Create a new `InstanceHandle` pointing at a new [`InstanceRef`].
808    ///
809    /// # Safety
810    ///
811    /// This method is not necessarily inherently unsafe to call, but in general
812    /// the APIs of an `Instance` are quite unsafe and have not been really
813    /// audited for safety that much. As a result the unsafety here on this
814    /// method is a low-overhead way of saying “this is an extremely unsafe type
815    /// to work with”.
816    ///
817    /// Extreme care must be taken when working with `InstanceHandle` and it's
818    /// recommended to have relatively intimate knowledge of how it works
819    /// internally if you'd like to do so. If possible it's recommended to use
820    /// the `near_vm` crate API rather than this type since that is vetted for
821    /// safety.
822    ///
823    /// However the following must be taken care of before calling this function:
824    /// - The memory at `instance.tables_ptr()` must be initialized with data for
825    ///   all the local tables.
826    /// - The memory at `instance.memories_ptr()` must be initialized with data for
827    ///   all the local memories.
828    // FIXME: instances should just store a reference to an Artifact
829    #[allow(clippy::too_many_arguments)]
830    pub unsafe fn new(
831        artifact: Arc<dyn Artifact>,
832        allocator: InstanceAllocator,
833        finished_memories: BoxedSlice<LocalMemoryIndex, Arc<LinearMemory>>,
834        finished_tables: BoxedSlice<LocalTableIndex, Arc<dyn Table>>,
835        finished_globals: BoxedSlice<LocalGlobalIndex, Arc<Global>>,
836        imports: Imports,
837        passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
838        host_state: Box<dyn Any>,
839        imported_function_envs: BoxedSlice<FunctionIndex, ImportFunctionEnv>,
840        instance_config: InstanceConfig,
841    ) -> Self {
842        let vmctx_globals = finished_globals
843            .values()
844            .map(|m| m.vmglobal())
845            .collect::<PrimaryMap<LocalGlobalIndex, _>>()
846            .into_boxed_slice();
847        let passive_data = RefCell::new(passive_data);
848
849        let handle = {
850            // use dummy value to create an instance so we can get the vmctx pointer
851            let funcrefs = PrimaryMap::new().into_boxed_slice();
852            // Create the `Instance`. The unique, the One.
853            let instance = Instance {
854                artifact,
855                config: instance_config.clone(),
856                memories: finished_memories,
857                tables: finished_tables,
858                globals: finished_globals,
859                passive_elements: Default::default(),
860                passive_data,
861                host_state,
862                funcrefs,
863                imported_function_envs,
864                vmctx: VMContext {},
865            };
866
867            let mut instance_ref = allocator.write_instance(instance);
868
869            // Set the funcrefs after we've built the instance
870            {
871                let instance = instance_ref.as_mut().unwrap();
872                let vmctx_ptr = instance.vmctx_ptr();
873                instance.funcrefs = build_funcrefs(
874                    &imports,
875                    instance.artifact.functions().iter().map(|(_, f)| f),
876                    vmctx_ptr,
877                );
878                unsafe {
879                    *(instance.trap_catcher_ptr()) = get_trap_handler();
880                    *(instance.gas_counter_ptr()) = instance_config.gas_counter;
881                    *(instance.stack_limit_ptr()) = instance_config.stack_limit;
882                    *(instance.stack_limit_initial_ptr()) = instance_config.stack_limit;
883                }
884            }
885
886            Self { instance: instance_ref }
887        };
888        let instance = handle.instance().as_ref();
889
890        unsafe {
891            ptr::copy(
892                instance.artifact.signatures().as_ptr(),
893                instance.signature_ids_ptr() as *mut VMSharedSignatureIndex,
894                instance.artifact.signatures().len(),
895            );
896
897            ptr::copy(
898                imports.functions.values().as_slice().as_ptr(),
899                instance.imported_functions_ptr() as *mut VMFunctionImport,
900                imports.functions.len(),
901            );
902            ptr::copy(
903                imports.tables.values().as_slice().as_ptr(),
904                instance.imported_tables_ptr() as *mut VMTableImport,
905                imports.tables.len(),
906            );
907            ptr::copy(
908                imports.memories.values().as_slice().as_ptr(),
909                instance.imported_memories_ptr() as *mut VMMemoryImport,
910                imports.memories.len(),
911            );
912            ptr::copy(
913                imports.globals.values().as_slice().as_ptr(),
914                instance.imported_globals_ptr() as *mut VMGlobalImport,
915                imports.globals.len(),
916            );
917            // these should already be set, add asserts here? for:
918            // - instance.tables_ptr() as *mut VMTableDefinition
919            // - instance.memories_ptr() as *mut VMMemoryDefinition
920            ptr::copy(
921                vmctx_globals.values().as_slice().as_ptr(),
922                instance.globals_ptr() as *mut NonNull<VMGlobalDefinition>,
923                vmctx_globals.len(),
924            );
925            ptr::write(
926                instance.builtin_functions_ptr() as *mut VMBuiltinFunctionsArray,
927                VMBuiltinFunctionsArray::initialized(),
928            );
929        }
930
931        // Perform infallible initialization in this constructor, while fallible
932        // initialization is deferred to the `initialize` method.
933        initialize_passive_elements(instance);
934        initialize_globals(instance);
935        handle
936    }
937
938    /// Return a reference to the contained `Instance`.
939    pub fn instance(&self) -> &InstanceRef {
940        &self.instance
941    }
942
943    /// Finishes the instantiation process started by `Instance::new_with_config`.
944    ///
945    /// # Safety
946    ///
947    /// Only safe to call immediately after instantiation.
948    pub unsafe fn finish_instantiation(&self) -> Result<(), Trap> {
949        let instance = self.instance().as_ref();
950
951        // Apply the initializers.
952        initialize_tables(instance)?;
953        initialize_memories(instance, instance.artifact.data_segments().iter().map(Into::into))?;
954
955        // The WebAssembly spec specifies that the start function is
956        // invoked automatically at instantiation time.
957        instance.invoke_start_function()?;
958        Ok(())
959    }
960
961    /// See [`traphandlers::near_vm_call_trampoline`].
962    pub unsafe fn invoke_function(
963        &self,
964        vmctx: VMFunctionEnvironment,
965        trampoline: VMTrampoline,
966        callee: *const VMFunctionBody,
967        values_vec: *mut u8,
968    ) -> Result<(), Trap> {
969        // `vmctx` is always `*mut VMContext` here, as we call to WASM.
970        {
971            let instance = self.instance().as_ref();
972            instance.reset_stack_meter();
973        }
974        unsafe { near_vm_call_trampoline(vmctx, trampoline, callee, values_vec) }
975    }
976
977    /// Return a reference to the vmctx used by compiled wasm code.
978    pub fn vmctx(&self) -> &VMContext {
979        self.instance().as_ref().vmctx()
980    }
981
982    /// Return a raw pointer to the vmctx used by compiled wasm code.
983    pub fn vmctx_ptr(&self) -> *mut VMContext {
984        self.instance().as_ref().vmctx_ptr()
985    }
986
987    /// Return a reference to the `VMOffsets` to get offsets in the
988    /// `Self::vmctx_ptr` region. Be careful when doing pointer
989    /// arithmetic!
990    pub fn vmoffsets(&self) -> &VMOffsets {
991        self.instance().as_ref().offsets()
992    }
993
994    /// Lookup an exported function with the specified function index.
995    pub fn function_by_index(&self, idx: FunctionIndex) -> Option<VMFunction> {
996        let instance = self.instance.as_ref();
997
998        let (address, signature, vmctx, call_trampoline) =
999            match instance.artifact.import_counts().local_function_index(idx) {
1000                Ok(local) => {
1001                    let func = instance.artifact.functions().get(local)?;
1002                    (
1003                        *(func.body),
1004                        func.signature,
1005                        VMFunctionEnvironment { vmctx: instance.vmctx_ptr() },
1006                        Some(func.trampoline),
1007                    )
1008                }
1009                Err(import) => {
1010                    let import = instance.imported_function(import);
1011                    (*(import.body), import.signature, import.environment, import.trampoline)
1012                }
1013            };
1014        Some(VMFunction {
1015            // Any function received is already static at this point as:
1016            // 1. All locally defined functions in the Wasm have a static signature.
1017            // 2. All the imported functions are already static (because
1018            //    they point to the trampolines rather than the dynamic addresses).
1019            kind: VMFunctionKind::Static,
1020            address,
1021            signature,
1022            vmctx,
1023            call_trampoline,
1024            instance_ref: Some(WeakOrStrongInstanceRef::Strong(self.instance().clone())),
1025        })
1026    }
1027
1028    /// Return the indexed `VMMemoryDefinition`.
1029    fn memory_by_index(&self, index: MemoryIndex) -> Option<crate::VMMemory> {
1030        let instance = self.instance.as_ref();
1031        let from = match instance.artifact.import_counts().local_memory_index(index) {
1032            Ok(local) => Arc::clone(&instance.memories[local]),
1033            Err(import) => Arc::clone(&instance.imported_memory(import).from),
1034        };
1035        Some(crate::VMMemory::new(
1036            from,
1037            Some(WeakOrStrongInstanceRef::Strong(self.instance().clone())),
1038        ))
1039    }
1040
1041    /// Return the indexed `VMMemoryDefinition`.
1042    fn table_by_index(&self, index: TableIndex) -> Option<crate::VMTable> {
1043        let instance = self.instance.as_ref();
1044        let from = match instance.artifact.import_counts().local_table_index(index) {
1045            Ok(local) => Arc::clone(&instance.tables[local]),
1046            Err(import) => Arc::clone(&instance.imported_table(import).from),
1047        };
1048        Some(crate::VMTable {
1049            from,
1050            instance_ref: Some(WeakOrStrongInstanceRef::Strong(self.instance().clone())),
1051        })
1052    }
1053
1054    /// Obtain a reference to a global entity by its index.
1055    pub fn global_by_index(&self, index: GlobalIndex) -> Option<VMGlobal> {
1056        let instance = self.instance.as_ref();
1057        let from = match instance.artifact.import_counts().local_global_index(index) {
1058            Ok(local) => Arc::clone(&instance.globals[local]),
1059            Err(import) => Arc::clone(&instance.imported_global(import).from),
1060        };
1061        Some(crate::VMGlobal {
1062            from,
1063            instance_ref: Some(WeakOrStrongInstanceRef::Strong(self.instance().clone())),
1064        })
1065    }
1066
1067    /// Lookup an exported function with the given name.
1068    pub fn lookup(&self, field: &str) -> Option<VMExtern> {
1069        let instance = self.instance.as_ref();
1070        Some(match instance.artifact.export_field(field)? {
1071            ExportIndex::Function(idx) => VMExtern::Function(self.function_by_index(idx)?),
1072            ExportIndex::Table(idx) => VMExtern::Table(self.table_by_index(idx)?),
1073            ExportIndex::Global(idx) => VMExtern::Global(self.global_by_index(idx)?),
1074            ExportIndex::Memory(idx) => VMExtern::Memory(self.memory_by_index(idx)?),
1075        })
1076    }
1077
1078    /// Return a reference to the custom state attached to this instance.
1079    pub fn host_state(&self) -> &dyn Any {
1080        self.instance().as_ref().host_state()
1081    }
1082
1083    /// Return the memory index for the given `VMMemoryDefinition` in this instance.
1084    pub fn memory_index(&self, memory: &VMMemoryDefinition) -> LocalMemoryIndex {
1085        self.instance().as_ref().memory_index(memory)
1086    }
1087
1088    /// Grow memory in this instance by the specified amount of pages.
1089    ///
1090    /// Returns `None` if memory can't be grown by the specified amount
1091    /// of pages.
1092    pub fn memory_grow<IntoPages>(
1093        &self,
1094        memory_index: LocalMemoryIndex,
1095        delta: IntoPages,
1096    ) -> Result<Pages, MemoryError>
1097    where
1098        IntoPages: Into<Pages>,
1099    {
1100        self.instance().as_ref().memory_grow(memory_index, delta)
1101    }
1102
1103    /// Return the table index for the given `VMTableDefinition` in this instance.
1104    pub fn table_index(&self, table: &VMTableDefinition) -> LocalTableIndex {
1105        self.instance().as_ref().table_index(table)
1106    }
1107
1108    /// Grow table in this instance by the specified amount of pages.
1109    ///
1110    /// Returns `None` if memory can't be grown by the specified amount
1111    /// of pages.
1112    pub fn table_grow(
1113        &self,
1114        table_index: LocalTableIndex,
1115        delta: u32,
1116        init_value: TableElement,
1117    ) -> Option<u32> {
1118        self.instance().as_ref().table_grow(table_index, delta, init_value)
1119    }
1120
1121    /// Get table element reference.
1122    ///
1123    /// Returns `None` if index is out of bounds.
1124    pub fn table_get(&self, table_index: LocalTableIndex, index: u32) -> Option<TableElement> {
1125        self.instance().as_ref().table_get(table_index, index)
1126    }
1127
1128    /// Set table element reference.
1129    ///
1130    /// Returns an error if the index is out of bounds
1131    pub fn table_set(
1132        &self,
1133        table_index: LocalTableIndex,
1134        index: u32,
1135        val: TableElement,
1136    ) -> Result<(), Trap> {
1137        self.instance().as_ref().table_set(table_index, index, val)
1138    }
1139
1140    /// Get a table defined locally within this module.
1141    pub fn get_local_table(&self, index: LocalTableIndex) -> &dyn Table {
1142        self.instance().as_ref().get_local_table(index)
1143    }
1144}
1145
1146/// Initializes the host environments.
1147///
1148/// # Safety
1149/// - This function must be called with the correct `Err` type parameter: the error type is not
1150///   visible to code in `near_vm_vm`, so it's the caller's responsibility to ensure these
1151///   functions are called with the correct type.
1152/// - `instance_ptr` must point to a valid `near_vm_test_api::Instance`.
1153#[tracing::instrument(target = "near_vm", level = "trace", skip_all)]
1154pub unsafe fn initialize_host_envs<Err: Sized>(
1155    handle: &parking_lot::Mutex<InstanceHandle>,
1156    instance_ptr: *const ffi::c_void,
1157) -> Result<(), Err> {
1158    let initializers = {
1159        let mut instance_lock = handle.lock();
1160        let instance_ref = unsafe { instance_lock.instance.as_mut_unchecked() };
1161        let mut initializers = vec![];
1162        for import_function_env in instance_ref.imported_function_envs.values_mut() {
1163            match import_function_env {
1164                ImportFunctionEnv::Env { env, initializer, .. } => {
1165                    if let Some(init) = initializer.take() {
1166                        initializers.push((init, *env));
1167                    }
1168                }
1169                ImportFunctionEnv::NoEnv => (),
1170            }
1171        }
1172        initializers
1173    };
1174    for (init, env) in initializers {
1175        // SAFE: this is a function pointer signature cast modifying the return type… Making sure
1176        // invariants hold here is delegated to the caller.
1177        let f = unsafe {
1178            mem::transmute::<&ImportInitializerFuncPtr, &ImportInitializerFuncPtr<Err>>(&init)
1179        };
1180        f(env, instance_ptr)?;
1181    }
1182    Ok(())
1183}
1184
1185/// Compute the offset for a memory data initializer.
1186fn get_memory_init_start(init: &DataInitializer<'_>, instance: &Instance) -> usize {
1187    let mut start = init.location.offset;
1188    if let Some(base) = init.location.base {
1189        // SAFE: wasm checking verifies that globals referenced for base are u32.
1190        let val = unsafe { instance.global(base).to_u32() };
1191        start += usize::try_from(val).unwrap();
1192    }
1193    start
1194}
1195
1196#[allow(clippy::mut_from_ref)]
1197/// Return a byte-slice view of a memory's data.
1198///
1199/// # SAFETY
1200///
1201/// * Don't call this multiple times to create aliased mutable references, 'kay?
1202unsafe fn get_memory_slice<'instance>(
1203    init: &DataInitializer<'_>,
1204    instance: &'instance Instance,
1205) -> &'instance mut [u8] {
1206    let memory = instance.memory_definition(init.location.memory_index);
1207    unsafe { slice::from_raw_parts_mut(memory.base, memory.current_length) }
1208}
1209
1210/// Compute the offset for a table element initializer.
1211fn get_table_init_start(init: &OwnedTableInitializer, instance: &Instance) -> usize {
1212    let mut start = init.offset;
1213    if let Some(base) = init.base {
1214        // SAFE: wasm checking verifies that globals referenced for base are u32.
1215        let val = unsafe { instance.global(base).to_u32() };
1216        start += usize::try_from(val).unwrap();
1217    }
1218    start
1219}
1220
1221/// Initialize the table memory from the provided initializers.
1222fn initialize_tables(instance: &Instance) -> Result<(), Trap> {
1223    for init in instance.artifact.element_segments() {
1224        let start = get_table_init_start(init, instance);
1225        let table = instance.get_table(init.table_index);
1226
1227        if start.checked_add(init.elements.len()).map_or(true, |end| end > table.size() as usize) {
1228            return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
1229        }
1230
1231        for (i, func_idx) in init.elements.iter().enumerate() {
1232            let anyfunc = instance.get_vm_funcref(*func_idx);
1233            table.set(u32::try_from(start + i).unwrap(), TableElement::FuncRef(anyfunc)).unwrap();
1234        }
1235    }
1236
1237    Ok(())
1238}
1239
1240/// Initialize the `Instance::passive_elements` map by resolving the
1241/// `ModuleInfo::passive_elements`'s `FunctionIndex`s into `VMCallerCheckedAnyfunc`s for
1242/// this instance.
1243fn initialize_passive_elements(instance: &Instance) {
1244    let mut passive_elements = instance.passive_elements.borrow_mut();
1245    debug_assert!(
1246        passive_elements.is_empty(),
1247        "should only be called once, at initialization time"
1248    );
1249
1250    passive_elements.extend(
1251        instance
1252            .artifact
1253            .passive_elements()
1254            .iter()
1255            .filter(|(_, segments)| !segments.is_empty())
1256            .map(|(idx, segments)| {
1257                (*idx, segments.iter().map(|s| instance.get_vm_funcref(*s)).collect())
1258            }),
1259    );
1260}
1261
1262/// Initialize the table memory from the provided initializers.
1263fn initialize_memories<'a>(
1264    instance: &Instance,
1265    data_initializers: impl Iterator<Item = DataInitializer<'a>>,
1266) -> Result<(), Trap> {
1267    for init in data_initializers {
1268        let memory = instance.memory_definition(init.location.memory_index);
1269
1270        let start = get_memory_init_start(&init, instance);
1271        if start.checked_add(init.data.len()).map_or(true, |end| end > memory.current_length) {
1272            return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
1273        }
1274
1275        unsafe {
1276            let mem_slice = get_memory_slice(&init, instance);
1277            let end = start + init.data.len();
1278            let to_init = &mut mem_slice[start..end];
1279            to_init.copy_from_slice(init.data);
1280        }
1281    }
1282
1283    Ok(())
1284}
1285
1286fn initialize_globals(instance: &Instance) {
1287    for (index, (_, initializer)) in instance.artifact.globals().iter().enumerate() {
1288        unsafe {
1289            let to = instance.global_ptr(LocalGlobalIndex::new(index)).as_ptr();
1290            match initializer {
1291                GlobalInit::I32Const(x) => *(*to).as_i32_mut() = *x,
1292                GlobalInit::I64Const(x) => *(*to).as_i64_mut() = *x,
1293                GlobalInit::F32Const(x) => *(*to).as_f32_mut() = *x,
1294                GlobalInit::F64Const(x) => *(*to).as_f64_mut() = *x,
1295                GlobalInit::V128Const(x) => *(*to).as_bytes_mut() = *x.bytes(),
1296                GlobalInit::GetGlobal(x) => *to = instance.global(*x).clone(),
1297                GlobalInit::RefNullConst => *(*to).as_funcref_mut() = VMFuncRef::null(),
1298                GlobalInit::RefFunc(func_idx) => {
1299                    let funcref = instance.func_ref(*func_idx).unwrap();
1300                    *(*to).as_funcref_mut() = funcref;
1301                }
1302            }
1303        }
1304    }
1305}
1306
1307/// Eagerly builds all the `VMFuncRef`s for imported and local functions so that all
1308/// future funcref operations are just looking up this data.
1309pub fn build_funcrefs<'a>(
1310    imports: &Imports,
1311    finished_functions: impl ExactSizeIterator<Item = &'a VMLocalFunction>,
1312    // vmshared_signatures: &BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
1313    vmctx_ptr: *mut VMContext,
1314) -> BoxedSlice<FunctionIndex, VMCallerCheckedAnyfunc> {
1315    let mut func_refs =
1316        PrimaryMap::with_capacity(imports.functions.len() + finished_functions.len());
1317    for (_, import) in &imports.functions {
1318        let anyfunc = VMCallerCheckedAnyfunc {
1319            func_ptr: *(import.body),
1320            type_index: import.signature,
1321            vmctx: import.environment,
1322        };
1323        func_refs.push(anyfunc);
1324    }
1325    // local functions
1326    for function in finished_functions {
1327        let anyfunc = VMCallerCheckedAnyfunc {
1328            func_ptr: *(function.body),
1329            type_index: function.signature,
1330            vmctx: VMFunctionEnvironment { vmctx: vmctx_ptr },
1331        };
1332        func_refs.push(anyfunc);
1333    }
1334    func_refs.into_boxed_slice()
1335}