Skip to main content

substrate_wasmtime_runtime/
instance.rs

1//! An `Instance` contains all the runtime state used by execution of a
2//! wasm module (except its callstack and register state). An
3//! `InstanceHandle` is a reference-counting handle for an `Instance`.
4
5use crate::export::Export;
6use crate::imports::Imports;
7use crate::jit_int::GdbJitImageRegistration;
8use crate::memory::{DefaultMemoryCreator, RuntimeLinearMemory, RuntimeMemoryCreator};
9use crate::table::Table;
10use crate::traphandlers::Trap;
11use crate::vmcontext::{
12    VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport,
13    VMGlobalDefinition, VMGlobalImport, VMInterrupts, VMMemoryDefinition, VMMemoryImport,
14    VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline,
15};
16use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable};
17use memoffset::offset_of;
18use more_asserts::assert_lt;
19use std::alloc::{self, Layout};
20use std::any::Any;
21use std::cell::RefCell;
22use std::collections::HashMap;
23use std::convert::TryFrom;
24use std::sync::Arc;
25use std::{mem, ptr, slice};
26use thiserror::Error;
27use wasmtime_environ::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap};
28use wasmtime_environ::wasm::{
29    DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
30    ElemIndex, FuncIndex, GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex, TableIndex,
31};
32use wasmtime_environ::{ir, DataInitializer, EntityIndex, Module, TableElements, VMOffsets};
33
34/// A WebAssembly instance.
35///
36/// This is repr(C) to ensure that the vmctx field is last.
37#[repr(C)]
38pub(crate) struct Instance {
39    /// The `Module` this `Instance` was instantiated from.
40    module: Arc<Module>,
41
42    /// Offsets in the `vmctx` region.
43    offsets: VMOffsets,
44
45    /// WebAssembly linear memory data.
46    memories: BoxedSlice<DefinedMemoryIndex, Box<dyn RuntimeLinearMemory>>,
47
48    /// WebAssembly table data.
49    tables: BoxedSlice<DefinedTableIndex, Table>,
50
51    /// Passive elements in this instantiation. As `elem.drop`s happen, these
52    /// entries get removed. A missing entry is considered equivalent to an
53    /// empty slice.
54    passive_elements: RefCell<HashMap<ElemIndex, Box<[VMCallerCheckedAnyfunc]>>>,
55
56    /// Passive data segments from our module. As `data.drop`s happen, entries
57    /// get removed. A missing entry is considered equivalent to an empty slice.
58    passive_data: RefCell<HashMap<DataIndex, Arc<[u8]>>>,
59
60    /// Pointers to functions in executable memory.
61    finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
62
63    /// Pointers to trampoline functions used to enter particular signatures
64    trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
65
66    /// Hosts can store arbitrary per-instance information here.
67    host_state: Box<dyn Any>,
68
69    /// Optional image of JIT'ed code for debugger registration.
70    dbg_jit_registration: Option<Arc<GdbJitImageRegistration>>,
71
72    /// Externally allocated data indicating how this instance will be
73    /// interrupted.
74    pub(crate) interrupts: Arc<VMInterrupts>,
75
76    /// Additional context used by compiled wasm code. This field is last, and
77    /// represents a dynamically-sized array that extends beyond the nominal
78    /// end of the struct (similar to a flexible array member).
79    vmctx: VMContext,
80}
81
82#[allow(clippy::cast_ptr_alignment)]
83impl Instance {
84    /// Helper function to access various locations offset from our `*mut
85    /// VMContext` object.
86    unsafe fn vmctx_plus_offset<T>(&self, offset: u32) -> *mut T {
87        (self.vmctx_ptr() as *mut u8)
88            .add(usize::try_from(offset).unwrap())
89            .cast()
90    }
91
92    /// Return the indexed `VMSharedSignatureIndex`.
93    fn signature_id(&self, index: SignatureIndex) -> VMSharedSignatureIndex {
94        let index = usize::try_from(index.as_u32()).unwrap();
95        unsafe { *self.signature_ids_ptr().add(index) }
96    }
97
98    pub(crate) fn module(&self) -> &Arc<Module> {
99        &self.module
100    }
101
102    pub(crate) fn module_ref(&self) -> &Module {
103        &*self.module
104    }
105
106    /// Return a pointer to the `VMSharedSignatureIndex`s.
107    fn signature_ids_ptr(&self) -> *mut VMSharedSignatureIndex {
108        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_signature_ids_begin()) }
109    }
110
111    /// Return the indexed `VMFunctionImport`.
112    fn imported_function(&self, index: FuncIndex) -> &VMFunctionImport {
113        let index = usize::try_from(index.as_u32()).unwrap();
114        unsafe { &*self.imported_functions_ptr().add(index) }
115    }
116
117    /// Return a pointer to the `VMFunctionImport`s.
118    fn imported_functions_ptr(&self) -> *mut VMFunctionImport {
119        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_functions_begin()) }
120    }
121
122    /// Return the index `VMTableImport`.
123    fn imported_table(&self, index: TableIndex) -> &VMTableImport {
124        let index = usize::try_from(index.as_u32()).unwrap();
125        unsafe { &*self.imported_tables_ptr().add(index) }
126    }
127
128    /// Return a pointer to the `VMTableImports`s.
129    fn imported_tables_ptr(&self) -> *mut VMTableImport {
130        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_tables_begin()) }
131    }
132
133    /// Return the indexed `VMMemoryImport`.
134    fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport {
135        let index = usize::try_from(index.as_u32()).unwrap();
136        unsafe { &*self.imported_memories_ptr().add(index) }
137    }
138
139    /// Return a pointer to the `VMMemoryImport`s.
140    fn imported_memories_ptr(&self) -> *mut VMMemoryImport {
141        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_memories_begin()) }
142    }
143
144    /// Return the indexed `VMGlobalImport`.
145    fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport {
146        let index = usize::try_from(index.as_u32()).unwrap();
147        unsafe { &*self.imported_globals_ptr().add(index) }
148    }
149
150    /// Return a pointer to the `VMGlobalImport`s.
151    fn imported_globals_ptr(&self) -> *mut VMGlobalImport {
152        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_globals_begin()) }
153    }
154
155    /// Return the indexed `VMTableDefinition`.
156    #[allow(dead_code)]
157    fn table(&self, index: DefinedTableIndex) -> VMTableDefinition {
158        unsafe { *self.table_ptr(index) }
159    }
160
161    /// Updates the value for a defined table to `VMTableDefinition`.
162    fn set_table(&self, index: DefinedTableIndex, table: VMTableDefinition) {
163        unsafe {
164            *self.table_ptr(index) = table;
165        }
166    }
167
168    /// Return the indexed `VMTableDefinition`.
169    fn table_ptr(&self, index: DefinedTableIndex) -> *mut VMTableDefinition {
170        let index = usize::try_from(index.as_u32()).unwrap();
171        unsafe { self.tables_ptr().add(index) }
172    }
173
174    /// Return a pointer to the `VMTableDefinition`s.
175    fn tables_ptr(&self) -> *mut VMTableDefinition {
176        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_tables_begin()) }
177    }
178
179    /// Get a locally defined or imported memory.
180    pub(crate) fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinition {
181        if let Some(defined_index) = self.module.local.defined_memory_index(index) {
182            self.memory(defined_index)
183        } else {
184            let import = self.imported_memory(index);
185            *unsafe { import.from.as_ref().unwrap() }
186        }
187    }
188
189    /// Return the indexed `VMMemoryDefinition`.
190    fn memory(&self, index: DefinedMemoryIndex) -> VMMemoryDefinition {
191        unsafe { *self.memory_ptr(index) }
192    }
193
194    /// Set the indexed memory to `VMMemoryDefinition`.
195    fn set_memory(&self, index: DefinedMemoryIndex, mem: VMMemoryDefinition) {
196        unsafe {
197            *self.memory_ptr(index) = mem;
198        }
199    }
200
201    /// Return the indexed `VMMemoryDefinition`.
202    fn memory_ptr(&self, index: DefinedMemoryIndex) -> *mut VMMemoryDefinition {
203        let index = usize::try_from(index.as_u32()).unwrap();
204        unsafe { self.memories_ptr().add(index) }
205    }
206
207    /// Return a pointer to the `VMMemoryDefinition`s.
208    fn memories_ptr(&self) -> *mut VMMemoryDefinition {
209        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_memories_begin()) }
210    }
211
212    /// Return the indexed `VMGlobalDefinition`.
213    fn global(&self, index: DefinedGlobalIndex) -> VMGlobalDefinition {
214        unsafe { *self.global_ptr(index) }
215    }
216
217    /// Set the indexed global to `VMGlobalDefinition`.
218    #[allow(dead_code)]
219    fn set_global(&self, index: DefinedGlobalIndex, global: VMGlobalDefinition) {
220        unsafe {
221            *self.global_ptr(index) = global;
222        }
223    }
224
225    /// Return the indexed `VMGlobalDefinition`.
226    fn global_ptr(&self, index: DefinedGlobalIndex) -> *mut VMGlobalDefinition {
227        let index = usize::try_from(index.as_u32()).unwrap();
228        unsafe { self.globals_ptr().add(index) }
229    }
230
231    /// Return a pointer to the `VMGlobalDefinition`s.
232    fn globals_ptr(&self) -> *mut VMGlobalDefinition {
233        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_globals_begin()) }
234    }
235
236    /// Return a pointer to the `VMBuiltinFunctionsArray`.
237    fn builtin_functions_ptr(&self) -> *mut VMBuiltinFunctionsArray {
238        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_builtin_functions_begin()) }
239    }
240
241    /// Return a pointer to the interrupts structure
242    pub fn interrupts(&self) -> *mut *const VMInterrupts {
243        unsafe { self.vmctx_plus_offset(self.offsets.vmctx_interrupts()) }
244    }
245
246    /// Return a reference to the vmctx used by compiled wasm code.
247    pub fn vmctx(&self) -> &VMContext {
248        &self.vmctx
249    }
250
251    /// Return a raw pointer to the vmctx used by compiled wasm code.
252    pub fn vmctx_ptr(&self) -> *mut VMContext {
253        self.vmctx() as *const VMContext as *mut VMContext
254    }
255
256    /// Lookup an export with the given name.
257    pub fn lookup(&self, field: &str) -> Option<Export> {
258        let export = if let Some(export) = self.module.exports.get(field) {
259            export.clone()
260        } else {
261            return None;
262        };
263        Some(self.lookup_by_declaration(&export))
264    }
265
266    /// Lookup an export with the given export declaration.
267    pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
268        match export {
269            EntityIndex::Function(index) => {
270                let signature = self.signature_id(self.module.local.functions[*index]);
271                let (address, vmctx) =
272                    if let Some(def_index) = self.module.local.defined_func_index(*index) {
273                        (
274                            self.finished_functions[def_index] as *const _,
275                            self.vmctx_ptr(),
276                        )
277                    } else {
278                        let import = self.imported_function(*index);
279                        (import.body, import.vmctx)
280                    };
281                ExportFunction {
282                    address,
283                    signature,
284                    vmctx,
285                }
286                .into()
287            }
288            EntityIndex::Table(index) => {
289                let (definition, vmctx) =
290                    if let Some(def_index) = self.module.local.defined_table_index(*index) {
291                        (self.table_ptr(def_index), self.vmctx_ptr())
292                    } else {
293                        let import = self.imported_table(*index);
294                        (import.from, import.vmctx)
295                    };
296                ExportTable {
297                    definition,
298                    vmctx,
299                    table: self.module.local.table_plans[*index].clone(),
300                }
301                .into()
302            }
303            EntityIndex::Memory(index) => {
304                let (definition, vmctx) =
305                    if let Some(def_index) = self.module.local.defined_memory_index(*index) {
306                        (self.memory_ptr(def_index), self.vmctx_ptr())
307                    } else {
308                        let import = self.imported_memory(*index);
309                        (import.from, import.vmctx)
310                    };
311                ExportMemory {
312                    definition,
313                    vmctx,
314                    memory: self.module.local.memory_plans[*index].clone(),
315                }
316                .into()
317            }
318            EntityIndex::Global(index) => ExportGlobal {
319                definition: if let Some(def_index) = self.module.local.defined_global_index(*index)
320                {
321                    self.global_ptr(def_index)
322                } else {
323                    self.imported_global(*index).from
324                },
325                vmctx: self.vmctx_ptr(),
326                global: self.module.local.globals[*index],
327            }
328            .into(),
329        }
330    }
331
332    /// Return an iterator over the exports of this instance.
333    ///
334    /// Specifically, it provides access to the key-value pairs, where the keys
335    /// are export names, and the values are export declarations which can be
336    /// resolved `lookup_by_declaration`.
337    pub fn exports(&self) -> indexmap::map::Iter<String, EntityIndex> {
338        self.module.exports.iter()
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 the offset from the vmctx pointer to its containing Instance.
348    #[inline]
349    pub(crate) fn vmctx_offset() -> isize {
350        offset_of!(Self, vmctx) as isize
351    }
352
353    /// Return the table index for the given `VMTableDefinition`.
354    pub(crate) fn table_index(&self, table: &VMTableDefinition) -> DefinedTableIndex {
355        let offsets = &self.offsets;
356        let begin = unsafe {
357            (&self.vmctx as *const VMContext as *const u8)
358                .add(usize::try_from(offsets.vmctx_tables_begin()).unwrap())
359        } as *const VMTableDefinition;
360        let end: *const VMTableDefinition = table;
361        // TODO: Use `offset_from` once it stablizes.
362        let index = DefinedTableIndex::new(
363            (end as usize - begin as usize) / mem::size_of::<VMTableDefinition>(),
364        );
365        assert_lt!(index.index(), self.tables.len());
366        index
367    }
368
369    /// Return the memory index for the given `VMMemoryDefinition`.
370    pub(crate) fn memory_index(&self, memory: &VMMemoryDefinition) -> DefinedMemoryIndex {
371        let offsets = &self.offsets;
372        let begin = unsafe {
373            (&self.vmctx as *const VMContext as *const u8)
374                .add(usize::try_from(offsets.vmctx_memories_begin()).unwrap())
375        } as *const VMMemoryDefinition;
376        let end: *const VMMemoryDefinition = memory;
377        // TODO: Use `offset_from` once it stablizes.
378        let index = DefinedMemoryIndex::new(
379            (end as usize - begin as usize) / mem::size_of::<VMMemoryDefinition>(),
380        );
381        assert_lt!(index.index(), self.memories.len());
382        index
383    }
384
385    /// Grow memory by the specified amount of pages.
386    ///
387    /// Returns `None` if memory can't be grown by the specified amount
388    /// of pages.
389    pub(crate) fn memory_grow(&self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
390        let result = self
391            .memories
392            .get(memory_index)
393            .unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
394            .grow(delta);
395
396        // Keep current the VMContext pointers used by compiled wasm code.
397        self.set_memory(memory_index, self.memories[memory_index].vmmemory());
398
399        result
400    }
401
402    /// Grow imported memory by the specified amount of pages.
403    ///
404    /// Returns `None` if memory can't be grown by the specified amount
405    /// of pages.
406    ///
407    /// # Safety
408    /// This and `imported_memory_size` are currently unsafe because they
409    /// dereference the memory import's pointers.
410    pub(crate) unsafe fn imported_memory_grow(
411        &self,
412        memory_index: MemoryIndex,
413        delta: u32,
414    ) -> Option<u32> {
415        let import = self.imported_memory(memory_index);
416        let foreign_instance = (&*import.vmctx).instance();
417        let foreign_memory = &*import.from;
418        let foreign_index = foreign_instance.memory_index(foreign_memory);
419
420        foreign_instance.memory_grow(foreign_index, delta)
421    }
422
423    /// Returns the number of allocated wasm pages.
424    pub(crate) fn memory_size(&self, memory_index: DefinedMemoryIndex) -> u32 {
425        self.memories
426            .get(memory_index)
427            .unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
428            .size()
429    }
430
431    /// Returns the number of allocated wasm pages in an imported memory.
432    ///
433    /// # Safety
434    /// This and `imported_memory_grow` are currently unsafe because they
435    /// dereference the memory import's pointers.
436    pub(crate) unsafe fn imported_memory_size(&self, memory_index: MemoryIndex) -> u32 {
437        let import = self.imported_memory(memory_index);
438        let foreign_instance = (&mut *import.vmctx).instance();
439        let foreign_memory = &mut *import.from;
440        let foreign_index = foreign_instance.memory_index(foreign_memory);
441
442        foreign_instance.memory_size(foreign_index)
443    }
444
445    /// Grow table by the specified amount of elements.
446    ///
447    /// Returns `None` if table can't be grown by the specified amount
448    /// of elements.
449    pub(crate) fn table_grow(&self, table_index: DefinedTableIndex, delta: u32) -> Option<u32> {
450        let result = self
451            .tables
452            .get(table_index)
453            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
454            .grow(delta);
455
456        // Keep current the VMContext pointers used by compiled wasm code.
457        self.set_table(table_index, self.tables[table_index].vmtable());
458
459        result
460    }
461
462    // Get table element by index.
463    fn table_get(
464        &self,
465        table_index: DefinedTableIndex,
466        index: u32,
467    ) -> Option<VMCallerCheckedAnyfunc> {
468        self.tables
469            .get(table_index)
470            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
471            .get(index)
472    }
473
474    fn table_set(
475        &self,
476        table_index: DefinedTableIndex,
477        index: u32,
478        val: VMCallerCheckedAnyfunc,
479    ) -> Result<(), ()> {
480        self.tables
481            .get(table_index)
482            .unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
483            .set(index, val)
484    }
485
486    fn alloc_layout(&self) -> Layout {
487        let size = mem::size_of_val(self)
488            .checked_add(usize::try_from(self.offsets.size_of_vmctx()).unwrap())
489            .unwrap();
490        let align = mem::align_of_val(self);
491        Layout::from_size_align(size, align).unwrap()
492    }
493
494    /// Get a `VMCallerCheckedAnyfunc` for the given `FuncIndex`.
495    fn get_caller_checked_anyfunc(&self, index: FuncIndex) -> VMCallerCheckedAnyfunc {
496        if index == FuncIndex::reserved_value() {
497            return VMCallerCheckedAnyfunc::default();
498        }
499
500        let sig = self.module.local.functions[index];
501        let type_index = self.signature_id(sig);
502
503        let (func_ptr, vmctx) = if let Some(def_index) = self.module.local.defined_func_index(index)
504        {
505            (
506                self.finished_functions[def_index] as *const _,
507                self.vmctx_ptr(),
508            )
509        } else {
510            let import = self.imported_function(index);
511            (import.body, import.vmctx)
512        };
513        VMCallerCheckedAnyfunc {
514            func_ptr,
515            type_index,
516            vmctx,
517        }
518    }
519
520    /// The `table.init` operation: initializes a portion of a table with a
521    /// passive element.
522    ///
523    /// # Errors
524    ///
525    /// Returns a `Trap` error when the range within the table is out of bounds
526    /// or the range within the passive element is out of bounds.
527    pub(crate) fn table_init(
528        &self,
529        table_index: TableIndex,
530        elem_index: ElemIndex,
531        dst: u32,
532        src: u32,
533        len: u32,
534    ) -> Result<(), Trap> {
535        // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init
536
537        let table = self.get_table(table_index);
538        let passive_elements = self.passive_elements.borrow();
539        let elem = passive_elements
540            .get(&elem_index)
541            .map(|e| &**e)
542            .unwrap_or_else(|| &[]);
543
544        if src
545            .checked_add(len)
546            .map_or(true, |n| n as usize > elem.len())
547            || dst.checked_add(len).map_or(true, |m| m > table.size())
548        {
549            return Err(Trap::wasm(ir::TrapCode::TableOutOfBounds));
550        }
551
552        // TODO(#983): investigate replacing this get/set loop with a `memcpy`.
553        for (dst, src) in (dst..dst + len).zip(src..src + len) {
554            table
555                .set(dst, elem[src as usize].clone())
556                .expect("should never panic because we already did the bounds check above");
557        }
558
559        Ok(())
560    }
561
562    /// Drop an element.
563    pub(crate) fn elem_drop(&self, elem_index: ElemIndex) {
564        // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop
565
566        let mut passive_elements = self.passive_elements.borrow_mut();
567        passive_elements.remove(&elem_index);
568        // Note that we don't check that we actually removed an element because
569        // dropping a non-passive element is a no-op (not a trap).
570    }
571
572    /// Do a `memory.copy` for a locally defined memory.
573    ///
574    /// # Errors
575    ///
576    /// Returns a `Trap` error when the source or destination ranges are out of
577    /// bounds.
578    pub(crate) fn defined_memory_copy(
579        &self,
580        memory_index: DefinedMemoryIndex,
581        dst: u32,
582        src: u32,
583        len: u32,
584    ) -> Result<(), Trap> {
585        // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy
586
587        let memory = self.memory(memory_index);
588
589        if src
590            .checked_add(len)
591            .map_or(true, |n| n as usize > memory.current_length)
592            || dst
593                .checked_add(len)
594                .map_or(true, |m| m as usize > memory.current_length)
595        {
596            return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
597        }
598
599        let dst = usize::try_from(dst).unwrap();
600        let src = usize::try_from(src).unwrap();
601
602        // Bounds and casts are checked above, by this point we know that
603        // everything is safe.
604        unsafe {
605            let dst = memory.base.add(dst);
606            let src = memory.base.add(src);
607            ptr::copy(src, dst, len as usize);
608        }
609
610        Ok(())
611    }
612
613    /// Perform a `memory.copy` on an imported memory.
614    pub(crate) fn imported_memory_copy(
615        &self,
616        memory_index: MemoryIndex,
617        dst: u32,
618        src: u32,
619        len: u32,
620    ) -> Result<(), Trap> {
621        let import = self.imported_memory(memory_index);
622        unsafe {
623            let foreign_instance = (&*import.vmctx).instance();
624            let foreign_memory = &*import.from;
625            let foreign_index = foreign_instance.memory_index(foreign_memory);
626            foreign_instance.defined_memory_copy(foreign_index, dst, src, len)
627        }
628    }
629
630    /// Perform the `memory.fill` operation on a locally defined memory.
631    ///
632    /// # Errors
633    ///
634    /// Returns a `Trap` error if the memory range is out of bounds.
635    pub(crate) fn defined_memory_fill(
636        &self,
637        memory_index: DefinedMemoryIndex,
638        dst: u32,
639        val: u32,
640        len: u32,
641    ) -> Result<(), Trap> {
642        let memory = self.memory(memory_index);
643
644        if dst
645            .checked_add(len)
646            .map_or(true, |m| m as usize > memory.current_length)
647        {
648            return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
649        }
650
651        let dst = isize::try_from(dst).unwrap();
652        let val = val as u8;
653
654        // Bounds and casts are checked above, by this point we know that
655        // everything is safe.
656        unsafe {
657            let dst = memory.base.offset(dst);
658            ptr::write_bytes(dst, val, len as usize);
659        }
660
661        Ok(())
662    }
663
664    /// Perform the `memory.fill` operation on an imported memory.
665    ///
666    /// # Errors
667    ///
668    /// Returns a `Trap` error if the memory range is out of bounds.
669    pub(crate) fn imported_memory_fill(
670        &self,
671        memory_index: MemoryIndex,
672        dst: u32,
673        val: u32,
674        len: u32,
675    ) -> Result<(), Trap> {
676        let import = self.imported_memory(memory_index);
677        unsafe {
678            let foreign_instance = (&*import.vmctx).instance();
679            let foreign_memory = &*import.from;
680            let foreign_index = foreign_instance.memory_index(foreign_memory);
681            foreign_instance.defined_memory_fill(foreign_index, dst, val, len)
682        }
683    }
684
685    /// Performs the `memory.init` operation.
686    ///
687    /// # Errors
688    ///
689    /// Returns a `Trap` error if the destination range is out of this module's
690    /// memory's bounds or if the source range is outside the data segment's
691    /// bounds.
692    pub(crate) fn memory_init(
693        &self,
694        memory_index: MemoryIndex,
695        data_index: DataIndex,
696        dst: u32,
697        src: u32,
698        len: u32,
699    ) -> Result<(), Trap> {
700        // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init
701
702        let memory = self.get_memory(memory_index);
703        let passive_data = self.passive_data.borrow();
704        let data = passive_data
705            .get(&data_index)
706            .map_or(&[][..], |data| &**data);
707
708        if src
709            .checked_add(len)
710            .map_or(true, |n| n as usize > data.len())
711            || dst
712                .checked_add(len)
713                .map_or(true, |m| m as usize > memory.current_length)
714        {
715            return Err(Trap::wasm(ir::TrapCode::HeapOutOfBounds));
716        }
717
718        let src_slice = &data[src as usize..(src + len) as usize];
719
720        unsafe {
721            let dst_start = memory.base.add(dst as usize);
722            let dst_slice = slice::from_raw_parts_mut(dst_start, len as usize);
723            dst_slice.copy_from_slice(src_slice);
724        }
725
726        Ok(())
727    }
728
729    /// Drop the given data segment, truncating its length to zero.
730    pub(crate) fn data_drop(&self, data_index: DataIndex) {
731        let mut passive_data = self.passive_data.borrow_mut();
732        passive_data.remove(&data_index);
733    }
734
735    /// Get a table by index regardless of whether it is locally-defined or an
736    /// imported, foreign table.
737    pub(crate) fn get_table(&self, table_index: TableIndex) -> &Table {
738        if let Some(defined_table_index) = self.module.local.defined_table_index(table_index) {
739            self.get_defined_table(defined_table_index)
740        } else {
741            self.get_foreign_table(table_index)
742        }
743    }
744
745    /// Get a locally-defined table.
746    pub(crate) fn get_defined_table(&self, index: DefinedTableIndex) -> &Table {
747        &self.tables[index]
748    }
749
750    /// Get an imported, foreign table.
751    pub(crate) fn get_foreign_table(&self, index: TableIndex) -> &Table {
752        let import = self.imported_table(index);
753        let foreign_instance = unsafe { (&mut *(import).vmctx).instance() };
754        let foreign_table = unsafe { &mut *(import).from };
755        let foreign_index = foreign_instance.table_index(foreign_table);
756        &foreign_instance.tables[foreign_index]
757    }
758}
759
760/// A handle holding an `Instance` of a WebAssembly module.
761#[derive(Hash, PartialEq, Eq)]
762pub struct InstanceHandle {
763    instance: *mut Instance,
764}
765
766unsafe impl Send for InstanceHandle {}
767
768impl InstanceHandle {
769    /// Create a new `InstanceHandle` pointing at a new `Instance`.
770    ///
771    /// # Unsafety
772    ///
773    /// This method is not necessarily inherently unsafe to call, but in general
774    /// the APIs of an `Instance` are quite unsafe and have not been really
775    /// audited for safety that much. As a result the unsafety here on this
776    /// method is a low-overhead way of saying "this is an extremely unsafe type
777    /// to work with".
778    ///
779    /// Extreme care must be taken when working with `InstanceHandle` and it's
780    /// recommended to have relatively intimate knowledge of how it works
781    /// internally if you'd like to do so. If possible it's recommended to use
782    /// the `wasmtime` crate API rather than this type since that is vetted for
783    /// safety.
784    pub unsafe fn new(
785        module: Arc<Module>,
786        finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
787        trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
788        imports: Imports,
789        mem_creator: Option<&dyn RuntimeMemoryCreator>,
790        vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
791        dbg_jit_registration: Option<Arc<GdbJitImageRegistration>>,
792        host_state: Box<dyn Any>,
793        interrupts: Arc<VMInterrupts>,
794    ) -> Result<Self, InstantiationError> {
795        let tables = create_tables(&module);
796        let memories = create_memories(&module, mem_creator.unwrap_or(&DefaultMemoryCreator {}))?;
797
798        let vmctx_tables = tables
799            .values()
800            .map(Table::vmtable)
801            .collect::<PrimaryMap<DefinedTableIndex, _>>()
802            .into_boxed_slice();
803
804        let vmctx_memories = memories
805            .values()
806            .map(|a| a.vmmemory())
807            .collect::<PrimaryMap<DefinedMemoryIndex, _>>()
808            .into_boxed_slice();
809
810        let vmctx_globals = create_globals(&module);
811
812        let offsets = VMOffsets::new(mem::size_of::<*const u8>() as u8, &module.local);
813
814        let passive_data = RefCell::new(module.passive_data.clone());
815
816        let handle = {
817            let instance = Instance {
818                module,
819                offsets,
820                memories,
821                tables,
822                passive_elements: Default::default(),
823                passive_data,
824                finished_functions,
825                trampolines,
826                dbg_jit_registration,
827                host_state,
828                interrupts,
829                vmctx: VMContext {},
830            };
831            let layout = instance.alloc_layout();
832            let instance_ptr = alloc::alloc(layout) as *mut Instance;
833            if instance_ptr.is_null() {
834                alloc::handle_alloc_error(layout);
835            }
836            ptr::write(instance_ptr, instance);
837            InstanceHandle {
838                instance: instance_ptr,
839            }
840        };
841        let instance = handle.instance();
842
843        ptr::copy(
844            vmshared_signatures.values().as_slice().as_ptr(),
845            instance.signature_ids_ptr() as *mut VMSharedSignatureIndex,
846            vmshared_signatures.len(),
847        );
848        ptr::copy(
849            imports.functions.values().as_slice().as_ptr(),
850            instance.imported_functions_ptr() as *mut VMFunctionImport,
851            imports.functions.len(),
852        );
853        ptr::copy(
854            imports.tables.values().as_slice().as_ptr(),
855            instance.imported_tables_ptr() as *mut VMTableImport,
856            imports.tables.len(),
857        );
858        ptr::copy(
859            imports.memories.values().as_slice().as_ptr(),
860            instance.imported_memories_ptr() as *mut VMMemoryImport,
861            imports.memories.len(),
862        );
863        ptr::copy(
864            imports.globals.values().as_slice().as_ptr(),
865            instance.imported_globals_ptr() as *mut VMGlobalImport,
866            imports.globals.len(),
867        );
868        ptr::copy(
869            vmctx_tables.values().as_slice().as_ptr(),
870            instance.tables_ptr() as *mut VMTableDefinition,
871            vmctx_tables.len(),
872        );
873        ptr::copy(
874            vmctx_memories.values().as_slice().as_ptr(),
875            instance.memories_ptr() as *mut VMMemoryDefinition,
876            vmctx_memories.len(),
877        );
878        ptr::copy(
879            vmctx_globals.values().as_slice().as_ptr(),
880            instance.globals_ptr() as *mut VMGlobalDefinition,
881            vmctx_globals.len(),
882        );
883        ptr::write(
884            instance.builtin_functions_ptr() as *mut VMBuiltinFunctionsArray,
885            VMBuiltinFunctionsArray::initialized(),
886        );
887        *instance.interrupts() = &*instance.interrupts;
888
889        // Perform infallible initialization in this constructor, while fallible
890        // initialization is deferred to the `initialize` method.
891        initialize_passive_elements(instance);
892        initialize_globals(instance);
893
894        Ok(handle)
895    }
896
897    /// Finishes the instantiation process started by `Instance::new`.
898    ///
899    /// Only safe to call immediately after instantiation.
900    pub unsafe fn initialize(
901        &self,
902        is_bulk_memory: bool,
903        data_initializers: &[DataInitializer<'_>],
904    ) -> Result<(), InstantiationError> {
905        // Check initializer bounds before initializing anything. Only do this
906        // when bulk memory is disabled, since the bulk memory proposal changes
907        // instantiation such that the intermediate results of failed
908        // initializations are visible.
909        if !is_bulk_memory {
910            check_table_init_bounds(self.instance())?;
911            check_memory_init_bounds(self.instance(), data_initializers)?;
912        }
913
914        // Apply fallible initializers. Note that this can "leak" state even if
915        // it fails.
916        initialize_tables(self.instance())?;
917        initialize_memories(self.instance(), data_initializers)?;
918
919        Ok(())
920    }
921
922    /// Create a new `InstanceHandle` pointing at the instance
923    /// pointed to by the given `VMContext` pointer.
924    ///
925    /// # Safety
926    /// This is unsafe because it doesn't work on just any `VMContext`, it must
927    /// be a `VMContext` allocated as part of an `Instance`.
928    pub unsafe fn from_vmctx(vmctx: *mut VMContext) -> Self {
929        let instance = (&mut *vmctx).instance();
930        Self {
931            instance: instance as *const Instance as *mut Instance,
932        }
933    }
934
935    /// Return a reference to the vmctx used by compiled wasm code.
936    pub fn vmctx(&self) -> &VMContext {
937        self.instance().vmctx()
938    }
939
940    /// Return a raw pointer to the vmctx used by compiled wasm code.
941    pub fn vmctx_ptr(&self) -> *mut VMContext {
942        self.instance().vmctx_ptr()
943    }
944
945    /// Return a reference-counting pointer to a module.
946    pub fn module(&self) -> &Arc<Module> {
947        self.instance().module()
948    }
949
950    /// Return a reference to a module.
951    pub fn module_ref(&self) -> &Module {
952        self.instance().module_ref()
953    }
954
955    /// Lookup an export with the given name.
956    pub fn lookup(&self, field: &str) -> Option<Export> {
957        self.instance().lookup(field)
958    }
959
960    /// Lookup an export with the given export declaration.
961    pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
962        self.instance().lookup_by_declaration(export)
963    }
964
965    /// Return an iterator over the exports of this instance.
966    ///
967    /// Specifically, it provides access to the key-value pairs, where the keys
968    /// are export names, and the values are export declarations which can be
969    /// resolved `lookup_by_declaration`.
970    pub fn exports(&self) -> indexmap::map::Iter<String, EntityIndex> {
971        self.instance().exports()
972    }
973
974    /// Return a reference to the custom state attached to this instance.
975    pub fn host_state(&self) -> &dyn Any {
976        self.instance().host_state()
977    }
978
979    /// Return the memory index for the given `VMMemoryDefinition` in this instance.
980    pub fn memory_index(&self, memory: &VMMemoryDefinition) -> DefinedMemoryIndex {
981        self.instance().memory_index(memory)
982    }
983
984    /// Grow memory in this instance by the specified amount of pages.
985    ///
986    /// Returns `None` if memory can't be grown by the specified amount
987    /// of pages.
988    pub fn memory_grow(&self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
989        self.instance().memory_grow(memory_index, delta)
990    }
991
992    /// Return the table index for the given `VMTableDefinition` in this instance.
993    pub fn table_index(&self, table: &VMTableDefinition) -> DefinedTableIndex {
994        self.instance().table_index(table)
995    }
996
997    /// Grow table in this instance by the specified amount of pages.
998    ///
999    /// Returns `None` if memory can't be grown by the specified amount
1000    /// of pages.
1001    pub fn table_grow(&self, table_index: DefinedTableIndex, delta: u32) -> Option<u32> {
1002        self.instance().table_grow(table_index, delta)
1003    }
1004
1005    /// Get table element reference.
1006    ///
1007    /// Returns `None` if index is out of bounds.
1008    pub fn table_get(
1009        &self,
1010        table_index: DefinedTableIndex,
1011        index: u32,
1012    ) -> Option<VMCallerCheckedAnyfunc> {
1013        self.instance().table_get(table_index, index)
1014    }
1015
1016    /// Set table element reference.
1017    ///
1018    /// Returns an error if the index is out of bounds
1019    pub fn table_set(
1020        &self,
1021        table_index: DefinedTableIndex,
1022        index: u32,
1023        val: VMCallerCheckedAnyfunc,
1024    ) -> Result<(), ()> {
1025        self.instance().table_set(table_index, index, val)
1026    }
1027
1028    /// Get a table defined locally within this module.
1029    pub fn get_defined_table(&self, index: DefinedTableIndex) -> &Table {
1030        self.instance().get_defined_table(index)
1031    }
1032
1033    /// Gets the trampoline pre-registered for a particular signature
1034    pub fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option<VMTrampoline> {
1035        self.instance().trampolines.get(&sig).cloned()
1036    }
1037
1038    /// Return a reference to the contained `Instance`.
1039    pub(crate) fn instance(&self) -> &Instance {
1040        unsafe { &*(self.instance as *const Instance) }
1041    }
1042
1043    /// Returns a clone of this instance.
1044    ///
1045    /// This is unsafe because the returned handle here is just a cheap clone
1046    /// of the internals, there's no lifetime tracking around its validity.
1047    /// You'll need to ensure that the returned handles all go out of scope at
1048    /// the same time.
1049    pub unsafe fn clone(&self) -> InstanceHandle {
1050        InstanceHandle {
1051            instance: self.instance,
1052        }
1053    }
1054
1055    /// Deallocates memory associated with this instance.
1056    ///
1057    /// Note that this is unsafe because there might be other handles to this
1058    /// `InstanceHandle` elsewhere, and there's nothing preventing usage of
1059    /// this handle after this function is called.
1060    pub unsafe fn dealloc(&self) {
1061        let instance = self.instance();
1062        let layout = instance.alloc_layout();
1063        ptr::drop_in_place(self.instance);
1064        alloc::dealloc(self.instance.cast(), layout);
1065    }
1066}
1067
1068fn check_table_init_bounds(instance: &Instance) -> Result<(), InstantiationError> {
1069    let module = Arc::clone(&instance.module);
1070    for init in &module.table_elements {
1071        let start = get_table_init_start(init, instance);
1072        let table = instance.get_table(init.table_index);
1073
1074        let size = usize::try_from(table.size()).unwrap();
1075        if size < start + init.elements.len() {
1076            return Err(InstantiationError::Link(LinkError(
1077                "table out of bounds: elements segment does not fit".to_owned(),
1078            )));
1079        }
1080    }
1081
1082    Ok(())
1083}
1084
1085/// Compute the offset for a memory data initializer.
1086fn get_memory_init_start(init: &DataInitializer<'_>, instance: &Instance) -> usize {
1087    let mut start = init.location.offset;
1088
1089    if let Some(base) = init.location.base {
1090        let val = unsafe {
1091            if let Some(def_index) = instance.module.local.defined_global_index(base) {
1092                *instance.global(def_index).as_u32()
1093            } else {
1094                *(*instance.imported_global(base).from).as_u32()
1095            }
1096        };
1097        start += usize::try_from(val).unwrap();
1098    }
1099
1100    start
1101}
1102
1103/// Return a byte-slice view of a memory's data.
1104unsafe fn get_memory_slice<'instance>(
1105    init: &DataInitializer<'_>,
1106    instance: &'instance Instance,
1107) -> &'instance mut [u8] {
1108    let memory = if let Some(defined_memory_index) = instance
1109        .module
1110        .local
1111        .defined_memory_index(init.location.memory_index)
1112    {
1113        instance.memory(defined_memory_index)
1114    } else {
1115        let import = instance.imported_memory(init.location.memory_index);
1116        let foreign_instance = (&mut *(import).vmctx).instance();
1117        let foreign_memory = &mut *(import).from;
1118        let foreign_index = foreign_instance.memory_index(foreign_memory);
1119        foreign_instance.memory(foreign_index)
1120    };
1121    slice::from_raw_parts_mut(memory.base, memory.current_length)
1122}
1123
1124fn check_memory_init_bounds(
1125    instance: &Instance,
1126    data_initializers: &[DataInitializer<'_>],
1127) -> Result<(), InstantiationError> {
1128    for init in data_initializers {
1129        let start = get_memory_init_start(init, instance);
1130        unsafe {
1131            let mem_slice = get_memory_slice(init, instance);
1132            if mem_slice.get_mut(start..start + init.data.len()).is_none() {
1133                return Err(InstantiationError::Link(LinkError(
1134                    "memory out of bounds: data segment does not fit".into(),
1135                )));
1136            }
1137        }
1138    }
1139
1140    Ok(())
1141}
1142
1143/// Allocate memory for just the tables of the current module.
1144fn create_tables(module: &Module) -> BoxedSlice<DefinedTableIndex, Table> {
1145    let num_imports = module.local.num_imported_tables;
1146    let mut tables: PrimaryMap<DefinedTableIndex, _> =
1147        PrimaryMap::with_capacity(module.local.table_plans.len() - num_imports);
1148    for table in &module.local.table_plans.values().as_slice()[num_imports..] {
1149        tables.push(Table::new(table));
1150    }
1151    tables.into_boxed_slice()
1152}
1153
1154/// Compute the offset for a table element initializer.
1155fn get_table_init_start(init: &TableElements, instance: &Instance) -> usize {
1156    let mut start = init.offset;
1157
1158    if let Some(base) = init.base {
1159        let val = unsafe {
1160            if let Some(def_index) = instance.module.local.defined_global_index(base) {
1161                *instance.global(def_index).as_u32()
1162            } else {
1163                *(*instance.imported_global(base).from).as_u32()
1164            }
1165        };
1166        start += usize::try_from(val).unwrap();
1167    }
1168
1169    start
1170}
1171
1172/// Initialize the table memory from the provided initializers.
1173fn initialize_tables(instance: &Instance) -> Result<(), InstantiationError> {
1174    let module = Arc::clone(&instance.module);
1175    for init in &module.table_elements {
1176        let start = get_table_init_start(init, instance);
1177        let table = instance.get_table(init.table_index);
1178
1179        if start
1180            .checked_add(init.elements.len())
1181            .map_or(true, |end| end > table.size() as usize)
1182        {
1183            return Err(InstantiationError::Trap(Trap::wasm(
1184                ir::TrapCode::HeapOutOfBounds,
1185            )));
1186        }
1187
1188        for (i, func_idx) in init.elements.iter().enumerate() {
1189            let anyfunc = instance.get_caller_checked_anyfunc(*func_idx);
1190            table
1191                .set(u32::try_from(start + i).unwrap(), anyfunc)
1192                .unwrap();
1193        }
1194    }
1195
1196    Ok(())
1197}
1198
1199/// Initialize the `Instance::passive_elements` map by resolving the
1200/// `Module::passive_elements`'s `FuncIndex`s into `VMCallerCheckedAnyfunc`s for
1201/// this instance.
1202fn initialize_passive_elements(instance: &Instance) {
1203    let mut passive_elements = instance.passive_elements.borrow_mut();
1204    debug_assert!(
1205        passive_elements.is_empty(),
1206        "should only be called once, at initialization time"
1207    );
1208
1209    passive_elements.extend(
1210        instance
1211            .module
1212            .passive_elements
1213            .iter()
1214            .filter(|(_, segments)| !segments.is_empty())
1215            .map(|(idx, segments)| {
1216                (
1217                    *idx,
1218                    segments
1219                        .iter()
1220                        .map(|s| instance.get_caller_checked_anyfunc(*s))
1221                        .collect(),
1222                )
1223            }),
1224    );
1225}
1226
1227/// Allocate memory for just the memories of the current module.
1228fn create_memories(
1229    module: &Module,
1230    mem_creator: &dyn RuntimeMemoryCreator,
1231) -> Result<BoxedSlice<DefinedMemoryIndex, Box<dyn RuntimeLinearMemory>>, InstantiationError> {
1232    let num_imports = module.local.num_imported_memories;
1233    let mut memories: PrimaryMap<DefinedMemoryIndex, _> =
1234        PrimaryMap::with_capacity(module.local.memory_plans.len() - num_imports);
1235    for plan in &module.local.memory_plans.values().as_slice()[num_imports..] {
1236        memories.push(
1237            mem_creator
1238                .new_memory(plan)
1239                .map_err(InstantiationError::Resource)?,
1240        );
1241    }
1242    Ok(memories.into_boxed_slice())
1243}
1244
1245/// Initialize the table memory from the provided initializers.
1246fn initialize_memories(
1247    instance: &Instance,
1248    data_initializers: &[DataInitializer<'_>],
1249) -> Result<(), InstantiationError> {
1250    for init in data_initializers {
1251        let memory = instance.get_memory(init.location.memory_index);
1252
1253        let start = get_memory_init_start(init, instance);
1254        if start
1255            .checked_add(init.data.len())
1256            .map_or(true, |end| end > memory.current_length)
1257        {
1258            return Err(InstantiationError::Trap(Trap::wasm(
1259                ir::TrapCode::HeapOutOfBounds,
1260            )));
1261        }
1262
1263        unsafe {
1264            let mem_slice = get_memory_slice(init, instance);
1265            let end = start + init.data.len();
1266            let to_init = &mut mem_slice[start..end];
1267            to_init.copy_from_slice(init.data);
1268        }
1269    }
1270
1271    Ok(())
1272}
1273
1274/// Allocate memory for just the globals of the current module,
1275/// with initializers applied.
1276fn create_globals(module: &Module) -> BoxedSlice<DefinedGlobalIndex, VMGlobalDefinition> {
1277    let num_imports = module.local.num_imported_globals;
1278    let mut vmctx_globals = PrimaryMap::with_capacity(module.local.globals.len() - num_imports);
1279
1280    for _ in &module.local.globals.values().as_slice()[num_imports..] {
1281        vmctx_globals.push(VMGlobalDefinition::new());
1282    }
1283
1284    vmctx_globals.into_boxed_slice()
1285}
1286
1287fn initialize_globals(instance: &Instance) {
1288    let module = Arc::clone(&instance.module);
1289    let num_imports = module.local.num_imported_globals;
1290    for (index, global) in module.local.globals.iter().skip(num_imports) {
1291        let def_index = module.local.defined_global_index(index).unwrap();
1292        unsafe {
1293            let to = instance.global_ptr(def_index);
1294            match global.initializer {
1295                GlobalInit::I32Const(x) => *(*to).as_i32_mut() = x,
1296                GlobalInit::I64Const(x) => *(*to).as_i64_mut() = x,
1297                GlobalInit::F32Const(x) => *(*to).as_f32_bits_mut() = x,
1298                GlobalInit::F64Const(x) => *(*to).as_f64_bits_mut() = x,
1299                GlobalInit::V128Const(x) => *(*to).as_u128_bits_mut() = x.0,
1300                GlobalInit::GetGlobal(x) => {
1301                    let from = if let Some(def_x) = module.local.defined_global_index(x) {
1302                        instance.global(def_x)
1303                    } else {
1304                        *instance.imported_global(x).from
1305                    };
1306                    *to = from;
1307                }
1308                GlobalInit::Import => panic!("locally-defined global initialized as import"),
1309                GlobalInit::RefNullConst | GlobalInit::RefFunc(_) => unimplemented!(),
1310            }
1311        }
1312    }
1313}
1314
1315/// An link error while instantiating a module.
1316#[derive(Error, Debug)]
1317#[error("Link error: {0}")]
1318pub struct LinkError(pub String);
1319
1320/// An error while instantiating a module.
1321#[derive(Error, Debug)]
1322pub enum InstantiationError {
1323    /// Insufficient resources available for execution.
1324    #[error("Insufficient resources: {0}")]
1325    Resource(String),
1326
1327    /// A wasm link error occured.
1328    #[error("Failed to link module")]
1329    Link(#[from] LinkError),
1330
1331    /// A trap ocurred during instantiation, after linking.
1332    #[error("Trap occurred during instantiation")]
1333    Trap(Trap),
1334
1335    /// A trap occurred while running the wasm start function.
1336    #[error("Trap occurred while invoking start function")]
1337    StartTrap(Trap),
1338}