1use 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#[repr(C)]
38pub(crate) struct Instance {
39 module: Arc<Module>,
41
42 offsets: VMOffsets,
44
45 memories: BoxedSlice<DefinedMemoryIndex, Box<dyn RuntimeLinearMemory>>,
47
48 tables: BoxedSlice<DefinedTableIndex, Table>,
50
51 passive_elements: RefCell<HashMap<ElemIndex, Box<[VMCallerCheckedAnyfunc]>>>,
55
56 passive_data: RefCell<HashMap<DataIndex, Arc<[u8]>>>,
59
60 finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
62
63 trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
65
66 host_state: Box<dyn Any>,
68
69 dbg_jit_registration: Option<Arc<GdbJitImageRegistration>>,
71
72 pub(crate) interrupts: Arc<VMInterrupts>,
75
76 vmctx: VMContext,
80}
81
82#[allow(clippy::cast_ptr_alignment)]
83impl Instance {
84 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 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 fn signature_ids_ptr(&self) -> *mut VMSharedSignatureIndex {
108 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_signature_ids_begin()) }
109 }
110
111 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 fn imported_functions_ptr(&self) -> *mut VMFunctionImport {
119 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_functions_begin()) }
120 }
121
122 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 fn imported_tables_ptr(&self) -> *mut VMTableImport {
130 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_tables_begin()) }
131 }
132
133 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 fn imported_memories_ptr(&self) -> *mut VMMemoryImport {
141 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_memories_begin()) }
142 }
143
144 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 fn imported_globals_ptr(&self) -> *mut VMGlobalImport {
152 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_globals_begin()) }
153 }
154
155 #[allow(dead_code)]
157 fn table(&self, index: DefinedTableIndex) -> VMTableDefinition {
158 unsafe { *self.table_ptr(index) }
159 }
160
161 fn set_table(&self, index: DefinedTableIndex, table: VMTableDefinition) {
163 unsafe {
164 *self.table_ptr(index) = table;
165 }
166 }
167
168 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 fn tables_ptr(&self) -> *mut VMTableDefinition {
176 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_tables_begin()) }
177 }
178
179 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 fn memory(&self, index: DefinedMemoryIndex) -> VMMemoryDefinition {
191 unsafe { *self.memory_ptr(index) }
192 }
193
194 fn set_memory(&self, index: DefinedMemoryIndex, mem: VMMemoryDefinition) {
196 unsafe {
197 *self.memory_ptr(index) = mem;
198 }
199 }
200
201 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 fn memories_ptr(&self) -> *mut VMMemoryDefinition {
209 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_memories_begin()) }
210 }
211
212 fn global(&self, index: DefinedGlobalIndex) -> VMGlobalDefinition {
214 unsafe { *self.global_ptr(index) }
215 }
216
217 #[allow(dead_code)]
219 fn set_global(&self, index: DefinedGlobalIndex, global: VMGlobalDefinition) {
220 unsafe {
221 *self.global_ptr(index) = global;
222 }
223 }
224
225 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 fn globals_ptr(&self) -> *mut VMGlobalDefinition {
233 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_globals_begin()) }
234 }
235
236 fn builtin_functions_ptr(&self) -> *mut VMBuiltinFunctionsArray {
238 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_builtin_functions_begin()) }
239 }
240
241 pub fn interrupts(&self) -> *mut *const VMInterrupts {
243 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_interrupts()) }
244 }
245
246 pub fn vmctx(&self) -> &VMContext {
248 &self.vmctx
249 }
250
251 pub fn vmctx_ptr(&self) -> *mut VMContext {
253 self.vmctx() as *const VMContext as *mut VMContext
254 }
255
256 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 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 pub fn exports(&self) -> indexmap::map::Iter<String, EntityIndex> {
338 self.module.exports.iter()
339 }
340
341 #[inline]
343 pub fn host_state(&self) -> &dyn Any {
344 &*self.host_state
345 }
346
347 #[inline]
349 pub(crate) fn vmctx_offset() -> isize {
350 offset_of!(Self, vmctx) as isize
351 }
352
353 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 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 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 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 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 self.set_memory(memory_index, self.memories[memory_index].vmmemory());
398
399 result
400 }
401
402 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 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 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 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 self.set_table(table_index, self.tables[table_index].vmtable());
458
459 result
460 }
461
462 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 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 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 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 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 pub(crate) fn elem_drop(&self, elem_index: ElemIndex) {
564 let mut passive_elements = self.passive_elements.borrow_mut();
567 passive_elements.remove(&elem_index);
568 }
571
572 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 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 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 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 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 unsafe {
657 let dst = memory.base.offset(dst);
658 ptr::write_bytes(dst, val, len as usize);
659 }
660
661 Ok(())
662 }
663
664 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 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 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 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 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 pub(crate) fn get_defined_table(&self, index: DefinedTableIndex) -> &Table {
747 &self.tables[index]
748 }
749
750 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#[derive(Hash, PartialEq, Eq)]
762pub struct InstanceHandle {
763 instance: *mut Instance,
764}
765
766unsafe impl Send for InstanceHandle {}
767
768impl InstanceHandle {
769 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 initialize_passive_elements(instance);
892 initialize_globals(instance);
893
894 Ok(handle)
895 }
896
897 pub unsafe fn initialize(
901 &self,
902 is_bulk_memory: bool,
903 data_initializers: &[DataInitializer<'_>],
904 ) -> Result<(), InstantiationError> {
905 if !is_bulk_memory {
910 check_table_init_bounds(self.instance())?;
911 check_memory_init_bounds(self.instance(), data_initializers)?;
912 }
913
914 initialize_tables(self.instance())?;
917 initialize_memories(self.instance(), data_initializers)?;
918
919 Ok(())
920 }
921
922 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 pub fn vmctx(&self) -> &VMContext {
937 self.instance().vmctx()
938 }
939
940 pub fn vmctx_ptr(&self) -> *mut VMContext {
942 self.instance().vmctx_ptr()
943 }
944
945 pub fn module(&self) -> &Arc<Module> {
947 self.instance().module()
948 }
949
950 pub fn module_ref(&self) -> &Module {
952 self.instance().module_ref()
953 }
954
955 pub fn lookup(&self, field: &str) -> Option<Export> {
957 self.instance().lookup(field)
958 }
959
960 pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
962 self.instance().lookup_by_declaration(export)
963 }
964
965 pub fn exports(&self) -> indexmap::map::Iter<String, EntityIndex> {
971 self.instance().exports()
972 }
973
974 pub fn host_state(&self) -> &dyn Any {
976 self.instance().host_state()
977 }
978
979 pub fn memory_index(&self, memory: &VMMemoryDefinition) -> DefinedMemoryIndex {
981 self.instance().memory_index(memory)
982 }
983
984 pub fn memory_grow(&self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
989 self.instance().memory_grow(memory_index, delta)
990 }
991
992 pub fn table_index(&self, table: &VMTableDefinition) -> DefinedTableIndex {
994 self.instance().table_index(table)
995 }
996
997 pub fn table_grow(&self, table_index: DefinedTableIndex, delta: u32) -> Option<u32> {
1002 self.instance().table_grow(table_index, delta)
1003 }
1004
1005 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 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 pub fn get_defined_table(&self, index: DefinedTableIndex) -> &Table {
1030 self.instance().get_defined_table(index)
1031 }
1032
1033 pub fn trampoline(&self, sig: VMSharedSignatureIndex) -> Option<VMTrampoline> {
1035 self.instance().trampolines.get(&sig).cloned()
1036 }
1037
1038 pub(crate) fn instance(&self) -> &Instance {
1040 unsafe { &*(self.instance as *const Instance) }
1041 }
1042
1043 pub unsafe fn clone(&self) -> InstanceHandle {
1050 InstanceHandle {
1051 instance: self.instance,
1052 }
1053 }
1054
1055 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
1085fn 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
1103unsafe 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
1143fn 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
1154fn 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
1172fn 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
1199fn 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
1227fn 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
1245fn 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
1274fn 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#[derive(Error, Debug)]
1317#[error("Link error: {0}")]
1318pub struct LinkError(pub String);
1319
1320#[derive(Error, Debug)]
1322pub enum InstantiationError {
1323 #[error("Insufficient resources: {0}")]
1325 Resource(String),
1326
1327 #[error("Failed to link module")]
1329 Link(#[from] LinkError),
1330
1331 #[error("Trap occurred during instantiation")]
1333 Trap(Trap),
1334
1335 #[error("Trap occurred while invoking start function")]
1337 StartTrap(Trap),
1338}