1mod allocator;
10
11use crate::LinearMemory;
12use crate::imports::Imports;
13use crate::store::{InternalStoreHandle, StoreObjects};
14use crate::table::TableElement;
15use crate::trap::{Trap, TrapCode};
16use crate::vmcontext::{
17 VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionContext,
18 VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition,
19 VMMemoryImport, VMSharedTagIndex, VMSignatureHash, VMTableDefinition, VMTableImport,
20 VMTrampoline, memory_copy, memory_fill, memory32_atomic_check_notify, memory32_atomic_check32,
21 memory32_atomic_check64,
22};
23use crate::{FunctionBodyPtr, MaybeInstanceOwned, TrapHandlerFn, VMTag, wasmer_call_trampoline};
24use crate::{VMConfig, VMFuncRef, VMFunction, VMGlobal, VMMemory, VMTable};
25use crate::{export::VMExtern, threadconditions::ExpectedValue};
26pub use allocator::InstanceAllocator;
27use core::mem::offset_of;
28use itertools::Itertools;
29use more_asserts::assert_lt;
30use std::alloc::Layout;
31use std::cell::RefCell;
32use std::collections::HashMap;
33use std::convert::TryFrom;
34use std::fmt;
35use std::mem;
36use std::ptr::{self, NonNull};
37use std::slice;
38use std::sync::Arc;
39use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap, packed_option::ReservedValue};
40use wasmer_types::{
41 DataIndex, DataInitializer, ElemIndex, ExportIndex, FunctionIndex, GlobalIndex, GlobalInit,
42 InitExpr, InitExprOp, LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex,
43 MemoryError, MemoryIndex, ModuleInfo, Pages, RawValue, SignatureIndex, TableIndex, TagIndex,
44 VMOffsets,
45};
46
47#[repr(C)]
54#[allow(clippy::type_complexity)]
55pub(crate) struct Instance {
56 module: Arc<ModuleInfo>,
58
59 context: *mut StoreObjects,
61
62 offsets: VMOffsets,
64
65 memories: BoxedSlice<LocalMemoryIndex, InternalStoreHandle<VMMemory>>,
67
68 tables: BoxedSlice<LocalTableIndex, InternalStoreHandle<VMTable>>,
70
71 table_allocation_room: u32,
73
74 globals: BoxedSlice<LocalGlobalIndex, InternalStoreHandle<VMGlobal>>,
76
77 tags: BoxedSlice<TagIndex, InternalStoreHandle<VMTag>>,
79
80 functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
82
83 function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
85
86 passive_elements: RefCell<HashMap<ElemIndex, Box<[Option<VMFuncRef>]>>>,
89
90 passive_data: RefCell<HashMap<DataIndex, Option<Arc<[u8]>>>>,
99
100 funcrefs: BoxedSlice<LocalFunctionIndex, VMCallerCheckedAnyfunc>,
103
104 imported_funcrefs: BoxedSlice<FunctionIndex, NonNull<VMCallerCheckedAnyfunc>>,
107
108 vmctx: VMContext,
113}
114
115impl fmt::Debug for Instance {
116 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
117 formatter.debug_struct("Instance").finish()
118 }
119}
120
121#[allow(clippy::cast_ptr_alignment)]
122impl Instance {
123 unsafe fn vmctx_plus_offset<T>(&self, offset: u32) -> *mut T {
126 unsafe {
127 (self.vmctx_ptr() as *mut u8)
128 .add(usize::try_from(offset).unwrap())
129 .cast()
130 }
131 }
132
133 fn module(&self) -> &Arc<ModuleInfo> {
134 &self.module
135 }
136
137 pub(crate) fn module_ref(&self) -> &ModuleInfo {
138 &self.module
139 }
140
141 pub(crate) fn context(&self) -> &StoreObjects {
142 unsafe { &*self.context }
143 }
144
145 pub(crate) fn context_mut(&mut self) -> &mut StoreObjects {
146 unsafe { &mut *self.context }
147 }
148
149 fn offsets(&self) -> &VMOffsets {
151 &self.offsets
152 }
153
154 fn imported_function(&self, index: FunctionIndex) -> &VMFunctionImport {
156 let index = usize::try_from(index.as_u32()).unwrap();
157 unsafe { &*self.imported_functions_ptr().add(index) }
158 }
159
160 fn imported_functions_ptr(&self) -> *mut VMFunctionImport {
162 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_functions_begin()) }
163 }
164
165 fn imported_table(&self, index: TableIndex) -> &VMTableImport {
167 let index = usize::try_from(index.as_u32()).unwrap();
168 unsafe { &*self.imported_tables_ptr().add(index) }
169 }
170
171 fn imported_tables_ptr(&self) -> *mut VMTableImport {
173 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_tables_begin()) }
174 }
175
176 fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport {
178 let index = usize::try_from(index.as_u32()).unwrap();
179 unsafe { &*self.imported_memories_ptr().add(index) }
180 }
181
182 fn imported_memories_ptr(&self) -> *mut VMMemoryImport {
184 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_memories_begin()) }
185 }
186
187 fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport {
189 let index = usize::try_from(index.as_u32()).unwrap();
190 unsafe { &*self.imported_globals_ptr().add(index) }
191 }
192
193 fn imported_globals_ptr(&self) -> *mut VMGlobalImport {
195 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_globals_begin()) }
196 }
197
198 #[cfg_attr(target_os = "windows", allow(dead_code))]
200 pub(crate) fn shared_tag_ptr(&self, index: TagIndex) -> &VMSharedTagIndex {
201 let index = usize::try_from(index.as_u32()).unwrap();
202 unsafe { &*self.shared_tags_ptr().add(index) }
203 }
204
205 pub(crate) fn shared_tags_ptr(&self) -> *mut VMSharedTagIndex {
207 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_tag_ids_begin()) }
208 }
209
210 #[allow(dead_code)]
212 fn table(&self, index: LocalTableIndex) -> VMTableDefinition {
213 unsafe { *self.table_ptr(index).as_ref() }
214 }
215
216 #[allow(dead_code)]
217 fn set_table(&self, index: LocalTableIndex, table: &VMTableDefinition) {
219 unsafe {
220 *self.table_ptr(index).as_ptr() = *table;
221 }
222 }
223
224 fn table_ptr(&self, index: LocalTableIndex) -> NonNull<VMTableDefinition> {
226 let index = usize::try_from(index.as_u32()).unwrap();
227 NonNull::new(unsafe { self.tables_ptr().add(index) }).unwrap()
228 }
229
230 fn tables_ptr(&self) -> *mut VMTableDefinition {
232 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_tables_begin()) }
233 }
234
235 fn fixed_funcref_table_ptr(
236 &self,
237 index: LocalTableIndex,
238 ) -> Option<NonNull<VMCallerCheckedAnyfunc>> {
239 let offset = self.offsets.vmctx_fixed_funcref_table_anyfuncs(index)?;
240 Some(NonNull::new(unsafe { self.vmctx_plus_offset(offset) }).unwrap())
241 }
242
243 fn sync_fixed_funcref_table_element(
244 &self,
245 table_index: LocalTableIndex,
246 index: u32,
247 funcref: Option<VMFuncRef>,
248 ) {
249 let Some(base) = self.fixed_funcref_table_ptr(table_index) else {
250 return;
251 };
252 unsafe {
253 *base.as_ptr().add(index as usize) = anyfunc_from_funcref(funcref);
254 }
255 }
256
257 fn sync_fixed_funcref_table(&self, table_index: LocalTableIndex) {
258 let Some(base) = self.fixed_funcref_table_ptr(table_index) else {
259 return;
260 };
261 let table = self.tables[table_index].get(self.context());
262 for index in 0..table.size() {
263 let TableElement::FuncRef(funcref) = table.get(index).unwrap() else {
264 unreachable!("fixed funcref tables cannot contain externrefs");
265 };
266 unsafe {
267 *base.as_ptr().add(index as usize) = anyfunc_from_funcref(funcref);
268 }
269 }
270 }
271
272 fn sync_fixed_funcref_table_by_index(&self, table_index: TableIndex) {
273 if let Some(local_table_index) = self.module.local_table_index(table_index) {
274 self.sync_fixed_funcref_table(local_table_index);
275 }
276 }
277
278 fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinition {
280 if let Some(local_index) = self.module.local_memory_index(index) {
281 self.memory(local_index)
282 } else {
283 let import = self.imported_memory(index);
284 unsafe { *import.definition.as_ref() }
285 }
286 }
287
288 fn memory(&self, index: LocalMemoryIndex) -> VMMemoryDefinition {
290 unsafe { *self.memory_ptr(index).as_ref() }
291 }
292
293 #[allow(dead_code)]
294 fn set_memory(&self, index: LocalMemoryIndex, mem: &VMMemoryDefinition) {
296 unsafe {
297 *self.memory_ptr(index).as_ptr() = *mem;
298 }
299 }
300
301 fn memory_ptr(&self, index: LocalMemoryIndex) -> NonNull<VMMemoryDefinition> {
303 let index = usize::try_from(index.as_u32()).unwrap();
304 NonNull::new(unsafe { self.memories_ptr().add(index) }).unwrap()
305 }
306
307 fn memories_ptr(&self) -> *mut VMMemoryDefinition {
309 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_memories_begin()) }
310 }
311
312 fn get_vmmemory(&self, index: MemoryIndex) -> &VMMemory {
314 if let Some(local_index) = self.module.local_memory_index(index) {
315 unsafe {
316 self.memories
317 .get(local_index)
318 .unwrap()
319 .get(self.context.as_ref().unwrap())
320 }
321 } else {
322 let import = self.imported_memory(index);
323 unsafe { import.handle.get(self.context.as_ref().unwrap()) }
324 }
325 }
326
327 fn get_vmmemory_mut(&mut self, index: MemoryIndex) -> &mut VMMemory {
329 if let Some(local_index) = self.module.local_memory_index(index) {
330 unsafe {
331 self.memories
332 .get_mut(local_index)
333 .unwrap()
334 .get_mut(self.context.as_mut().unwrap())
335 }
336 } else {
337 let import = self.imported_memory(index);
338 unsafe { import.handle.get_mut(self.context.as_mut().unwrap()) }
339 }
340 }
341
342 fn get_local_vmmemory_mut(&mut self, local_index: LocalMemoryIndex) -> &mut VMMemory {
344 unsafe {
345 self.memories
346 .get_mut(local_index)
347 .unwrap()
348 .get_mut(self.context.as_mut().unwrap())
349 }
350 }
351
352 fn global(&self, index: LocalGlobalIndex) -> VMGlobalDefinition {
354 unsafe { self.global_ptr(index).as_ref().clone() }
355 }
356
357 #[allow(dead_code)]
359 fn set_global(&self, index: LocalGlobalIndex, global: &VMGlobalDefinition) {
360 unsafe {
361 *self.global_ptr(index).as_ptr() = global.clone();
362 }
363 }
364
365 fn global_ptr(&self, index: LocalGlobalIndex) -> NonNull<VMGlobalDefinition> {
367 let index = usize::try_from(index.as_u32()).unwrap();
368 NonNull::new(unsafe { self.globals_ptr().add(index) }).unwrap()
369 }
370
371 fn globals_ptr(&self) -> *mut VMGlobalDefinition {
373 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_globals_begin()) }
374 }
375
376 fn builtin_functions_ptr(&self) -> *mut VMBuiltinFunctionsArray {
378 unsafe { self.vmctx_plus_offset(self.offsets.vmctx_builtin_functions_begin()) }
379 }
380
381 fn vmctx(&self) -> &VMContext {
383 &self.vmctx
384 }
385
386 fn vmctx_ptr(&self) -> *mut VMContext {
388 self.vmctx() as *const VMContext as *mut VMContext
389 }
390
391 fn invoke_start_function(
393 &self,
394 config: &VMConfig,
395 trap_handler: Option<*const TrapHandlerFn<'static>>,
396 ) -> Result<(), Trap> {
397 let start_index = match self.module.start_function {
398 Some(idx) => idx,
399 None => return Ok(()),
400 };
401
402 let (callee_address, callee_vmctx) = match self.module.local_func_index(start_index) {
403 Some(local_index) => {
404 let body = self
405 .functions
406 .get(local_index)
407 .expect("function index is out of bounds")
408 .0;
409 (
410 body as *const _,
411 VMFunctionContext {
412 vmctx: self.vmctx_ptr(),
413 },
414 )
415 }
416 None => {
417 assert_lt!(start_index.index(), self.module.num_imported_functions);
418 let import = self.imported_function(start_index);
419 (import.body, import.environment)
420 }
421 };
422
423 let sig = self.module.functions[start_index];
424 let trampoline = self.function_call_trampolines[sig];
425 let mut values_vec = vec![];
426
427 unsafe {
428 wasmer_call_trampoline(
432 trap_handler,
433 config,
434 callee_vmctx,
435 trampoline,
436 callee_address,
437 values_vec.as_mut_ptr(),
438 )
439 }
440 }
441
442 #[inline]
444 pub(crate) fn vmctx_offset() -> isize {
445 offset_of!(Self, vmctx) as isize
446 }
447
448 pub(crate) fn table_index(&self, table: &VMTableDefinition) -> LocalTableIndex {
450 let begin: *const VMTableDefinition = self.tables_ptr() as *const _;
451 let end: *const VMTableDefinition = table;
452 let index = LocalTableIndex::new(
454 (end as usize - begin as usize) / mem::size_of::<VMTableDefinition>(),
455 );
456 assert_lt!(index.index(), self.tables.len());
457 index
458 }
459
460 pub(crate) fn memory_index(&self, memory: &VMMemoryDefinition) -> LocalMemoryIndex {
462 let begin: *const VMMemoryDefinition = self.memories_ptr() as *const _;
463 let end: *const VMMemoryDefinition = memory;
464 let index = LocalMemoryIndex::new(
466 (end as usize - begin as usize) / mem::size_of::<VMMemoryDefinition>(),
467 );
468 assert_lt!(index.index(), self.memories.len());
469 index
470 }
471
472 pub(crate) fn memory_grow<IntoPages>(
477 &mut self,
478 memory_index: LocalMemoryIndex,
479 delta: IntoPages,
480 ) -> Result<Pages, MemoryError>
481 where
482 IntoPages: Into<Pages>,
483 {
484 let mem = *self
485 .memories
486 .get(memory_index)
487 .unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()));
488 mem.get_mut(self.context_mut()).grow(delta.into())
489 }
490
491 pub(crate) unsafe fn imported_memory_grow<IntoPages>(
500 &mut self,
501 memory_index: MemoryIndex,
502 delta: IntoPages,
503 ) -> Result<Pages, MemoryError>
504 where
505 IntoPages: Into<Pages>,
506 {
507 let import = self.imported_memory(memory_index);
508 let mem = import.handle;
509 mem.get_mut(self.context_mut()).grow(delta.into())
510 }
511
512 pub(crate) fn memory_size(&self, memory_index: LocalMemoryIndex) -> Pages {
514 let mem = *self
515 .memories
516 .get(memory_index)
517 .unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()));
518 mem.get(self.context()).size()
519 }
520
521 pub(crate) unsafe fn imported_memory_size(&self, memory_index: MemoryIndex) -> Pages {
527 let import = self.imported_memory(memory_index);
528 let mem = import.handle;
529 mem.get(self.context()).size()
530 }
531
532 pub(crate) fn table_size(&self, table_index: LocalTableIndex) -> u32 {
534 let table = self
535 .tables
536 .get(table_index)
537 .unwrap_or_else(|| panic!("no table for index {}", table_index.index()));
538 table.get(self.context()).size()
539 }
540
541 pub(crate) unsafe fn imported_table_size(&self, table_index: TableIndex) -> u32 {
546 let import = self.imported_table(table_index);
547 let table = import.handle;
548 table.get(self.context()).size()
549 }
550
551 pub(crate) fn table_grow(
556 &mut self,
557 table_index: LocalTableIndex,
558 delta: u32,
559 init_value: TableElement,
560 ) -> Option<u32> {
561 if delta > self.table_allocation_room {
562 return None;
563 }
564 let table = *self
565 .tables
566 .get(table_index)
567 .unwrap_or_else(|| panic!("no table for index {}", table_index.index()));
568 let result = table.get_mut(self.context_mut()).grow(delta, init_value);
569 if result.is_some() {
570 self.table_allocation_room -= delta;
571 }
572 result
573 }
574
575 pub(crate) unsafe fn imported_table_grow(
580 &mut self,
581 table_index: TableIndex,
582 delta: u32,
583 init_value: TableElement,
584 ) -> Option<u32> {
585 let import = self.imported_table(table_index);
586 let table = import.handle;
587 table.get_mut(self.context_mut()).grow(delta, init_value)
588 }
589
590 pub(crate) fn table_get(
592 &self,
593 table_index: LocalTableIndex,
594 index: u32,
595 ) -> Option<TableElement> {
596 let table = self
597 .tables
598 .get(table_index)
599 .unwrap_or_else(|| panic!("no table for index {}", table_index.index()));
600 table.get(self.context()).get(index)
601 }
602
603 pub(crate) unsafe fn imported_table_get(
608 &self,
609 table_index: TableIndex,
610 index: u32,
611 ) -> Option<TableElement> {
612 let import = self.imported_table(table_index);
613 let table = import.handle;
614 table.get(self.context()).get(index)
615 }
616
617 pub(crate) fn table_set(
619 &mut self,
620 table_index: LocalTableIndex,
621 index: u32,
622 val: TableElement,
623 ) -> Result<(), Trap> {
624 let table = *self
625 .tables
626 .get(table_index)
627 .unwrap_or_else(|| panic!("no table for index {}", table_index.index()));
628 let funcref = match &val {
629 TableElement::FuncRef(funcref) => Some(*funcref),
630 TableElement::ExternRef(_) => None,
631 };
632 table.get_mut(self.context_mut()).set(index, val)?;
633 if let Some(funcref) = funcref {
634 self.sync_fixed_funcref_table_element(table_index, index, funcref);
635 }
636 Ok(())
637 }
638
639 pub(crate) unsafe fn imported_table_set(
644 &mut self,
645 table_index: TableIndex,
646 index: u32,
647 val: TableElement,
648 ) -> Result<(), Trap> {
649 let import = self.imported_table(table_index);
650 let table = import.handle;
651 table.get_mut(self.context_mut()).set(index, val)
652 }
653
654 pub(crate) fn func_ref(&self, function_index: FunctionIndex) -> Option<VMFuncRef> {
656 if function_index == FunctionIndex::reserved_value() {
657 None
658 } else if let Some(local_function_index) = self.module.local_func_index(function_index) {
659 Some(VMFuncRef(NonNull::from(
660 &self.funcrefs[local_function_index],
661 )))
662 } else {
663 Some(VMFuncRef(self.imported_funcrefs[function_index]))
664 }
665 }
666
667 pub(crate) fn table_init(
675 &mut self,
676 table_index: TableIndex,
677 elem_index: ElemIndex,
678 dst: u32,
679 src: u32,
680 len: u32,
681 ) -> Result<(), Trap> {
682 let table = self.get_table_handle(table_index);
685 let table = unsafe { table.get_mut(&mut *self.context) };
686 let passive_elements = self.passive_elements.borrow();
687 let elem = passive_elements
688 .get(&elem_index)
689 .map_or::<&[Option<VMFuncRef>], _>(&[], |e| &**e);
690
691 if src.checked_add(len).is_none_or(|n| n as usize > elem.len())
692 || dst.checked_add(len).is_none_or(|m| m > table.size())
693 {
694 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
695 }
696
697 for (dst, src) in (dst..dst + len).zip(src..src + len) {
698 table
699 .set(dst, TableElement::FuncRef(elem[src as usize]))
700 .expect("should never panic because we already did the bounds check above");
701 }
702
703 self.sync_fixed_funcref_table_by_index(table_index);
704
705 Ok(())
706 }
707
708 pub(crate) fn table_fill(
714 &mut self,
715 table_index: TableIndex,
716 start_index: u32,
717 item: TableElement,
718 len: u32,
719 ) -> Result<(), Trap> {
720 let table = self.get_table(table_index);
723 let table_size = table.size() as usize;
724
725 if start_index
726 .checked_add(len)
727 .is_none_or(|n| n as usize > table_size)
728 {
729 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
730 }
731
732 for i in start_index..(start_index + len) {
733 table
734 .set(i, item.clone())
735 .expect("should never panic because we already did the bounds check above");
736 }
737
738 self.sync_fixed_funcref_table_by_index(table_index);
739
740 Ok(())
741 }
742
743 pub(crate) fn table_copy(
745 &mut self,
746 dst_table_index: TableIndex,
747 src_table_index: TableIndex,
748 dst: u32,
749 src: u32,
750 len: u32,
751 ) -> Result<(), Trap> {
752 let result = if dst_table_index == src_table_index {
753 let table = self.get_table(dst_table_index);
754 table.copy_within(dst, src, len)
755 } else {
756 let dst_table = self.get_table_handle(dst_table_index);
757 let src_table = self.get_table_handle(src_table_index);
758 if dst_table == src_table {
759 unsafe {
760 dst_table
761 .get_mut(&mut *self.context)
762 .copy_within(dst, src, len)
763 }
764 } else {
765 unsafe {
766 dst_table.get_mut(&mut *self.context).copy(
767 src_table.get(&*self.context),
768 dst,
769 src,
770 len,
771 )
772 }
773 }
774 };
775 result?;
776 self.sync_fixed_funcref_table_by_index(dst_table_index);
777
778 Ok(())
779 }
780
781 pub(crate) fn elem_drop(&self, elem_index: ElemIndex) {
783 let mut passive_elements = self.passive_elements.borrow_mut();
786 passive_elements.remove(&elem_index);
787 }
790
791 pub(crate) fn memory_copy(
798 &self,
799 dst_memory_index: MemoryIndex,
800 src_memory_index: MemoryIndex,
801 dst: u32,
802 src: u32,
803 len: u32,
804 ) -> Result<(), Trap> {
805 let dst_memory = self.get_memory(dst_memory_index);
806 let src_memory = self.get_memory(src_memory_index);
807 unsafe { memory_copy(&dst_memory, &src_memory, dst, src, len) }
809 }
810
811 pub(crate) fn local_memory_fill(
817 &self,
818 memory_index: LocalMemoryIndex,
819 dst: u32,
820 val: u32,
821 len: u32,
822 ) -> Result<(), Trap> {
823 let memory = self.memory(memory_index);
824 unsafe { memory_fill(&memory, dst, val, len) }
826 }
827
828 pub(crate) fn imported_memory_fill(
834 &self,
835 memory_index: MemoryIndex,
836 dst: u32,
837 val: u32,
838 len: u32,
839 ) -> Result<(), Trap> {
840 let import = self.imported_memory(memory_index);
841 let memory = unsafe { import.definition.as_ref() };
842 unsafe { memory_fill(memory, dst, val, len) }
844 }
845
846 pub(crate) fn memory_init(
854 &self,
855 memory_index: MemoryIndex,
856 data_index: DataIndex,
857 dst: u32,
858 src: u32,
859 len: u32,
860 ) -> Result<(), Trap> {
861 let memory = self.get_vmmemory(memory_index);
864 let passive_data = self.passive_data.borrow();
865 let data = passive_data
869 .get(&data_index)
870 .and_then(|d| d.as_deref())
871 .unwrap_or(&[]);
872
873 let current_length = unsafe { memory.vmmemory().as_ref().current_length };
874 if src.checked_add(len).is_none_or(|n| n as usize > data.len())
875 || dst
876 .checked_add(len)
877 .is_none_or(|m| usize::try_from(m).unwrap() > current_length)
878 {
879 return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
880 }
881 let src_slice = &data[src as usize..(src + len) as usize];
882 unsafe { memory.initialize_with_data(dst as usize, src_slice) }
883 }
884
885 pub(crate) fn data_drop(&self, data_index: DataIndex) {
887 let mut passive_data = self.passive_data.borrow_mut();
888 if let Some(slot) = passive_data.get_mut(&data_index) {
891 *slot = None;
892 }
893 }
894
895 pub(crate) fn get_table(&mut self, table_index: TableIndex) -> &mut VMTable {
898 if let Some(local_table_index) = self.module.local_table_index(table_index) {
899 self.get_local_table(local_table_index)
900 } else {
901 self.get_foreign_table(table_index)
902 }
903 }
904
905 pub(crate) fn get_local_table(&mut self, index: LocalTableIndex) -> &mut VMTable {
907 let table = self.tables[index];
908 table.get_mut(self.context_mut())
909 }
910
911 pub(crate) fn get_foreign_table(&mut self, index: TableIndex) -> &mut VMTable {
913 let import = self.imported_table(index);
914 let table = import.handle;
915 table.get_mut(self.context_mut())
916 }
917
918 pub(crate) fn get_table_handle(
921 &mut self,
922 table_index: TableIndex,
923 ) -> InternalStoreHandle<VMTable> {
924 if let Some(local_table_index) = self.module.local_table_index(table_index) {
925 self.tables[local_table_index]
926 } else {
927 self.imported_table(table_index).handle
928 }
929 }
930
931 unsafe fn memory_wait(
934 memory: &mut VMMemory,
935 dst: u32,
936 expected: ExpectedValue,
937 timeout: i64,
938 ) -> Result<u32, Trap> {
939 let timeout = if timeout < 0 {
940 None
941 } else {
942 Some(std::time::Duration::from_nanos(timeout as u64))
943 };
944 match unsafe { memory.do_wait(dst, expected, timeout) } {
945 Ok(count) => Ok(count),
946 Err(_err) => Err(Trap::lib(TrapCode::HostInterrupt)),
947 }
948 }
949
950 pub(crate) fn local_memory_wait32(
952 &mut self,
953 memory_index: LocalMemoryIndex,
954 dst: u32,
955 val: u32,
956 timeout: i64,
957 ) -> Result<u32, Trap> {
958 let memory = self.memory(memory_index);
959 let ret = unsafe { memory32_atomic_check32(&memory, dst, val) };
965
966 if let Ok(mut ret) = ret {
967 if ret == 0 {
968 let memory = self.get_local_vmmemory_mut(memory_index);
969 ret = unsafe { Self::memory_wait(memory, dst, ExpectedValue::U32(val), timeout)? };
971 }
972 Ok(ret)
973 } else {
974 ret
975 }
976 }
977
978 pub(crate) fn imported_memory_wait32(
980 &mut self,
981 memory_index: MemoryIndex,
982 dst: u32,
983 val: u32,
984 timeout: i64,
985 ) -> Result<u32, Trap> {
986 let import = self.imported_memory(memory_index);
987 let memory = unsafe { import.definition.as_ref() };
988 let ret = unsafe { memory32_atomic_check32(memory, dst, val) };
994
995 if let Ok(mut ret) = ret {
996 if ret == 0 {
997 let memory = self.get_vmmemory_mut(memory_index);
998 ret = unsafe { Self::memory_wait(memory, dst, ExpectedValue::U32(val), timeout)? };
1000 }
1001 Ok(ret)
1002 } else {
1003 ret
1004 }
1005 }
1006
1007 pub(crate) fn local_memory_wait64(
1009 &mut self,
1010 memory_index: LocalMemoryIndex,
1011 dst: u32,
1012 val: u64,
1013 timeout: i64,
1014 ) -> Result<u32, Trap> {
1015 let memory = self.memory(memory_index);
1016 let ret = unsafe { memory32_atomic_check64(&memory, dst, val) };
1022
1023 if let Ok(mut ret) = ret {
1024 if ret == 0 {
1025 let memory = self.get_local_vmmemory_mut(memory_index);
1026 ret = unsafe { Self::memory_wait(memory, dst, ExpectedValue::U64(val), timeout)? };
1028 }
1029 Ok(ret)
1030 } else {
1031 ret
1032 }
1033 }
1034
1035 pub(crate) fn imported_memory_wait64(
1037 &mut self,
1038 memory_index: MemoryIndex,
1039 dst: u32,
1040 val: u64,
1041 timeout: i64,
1042 ) -> Result<u32, Trap> {
1043 let import = self.imported_memory(memory_index);
1044 let memory = unsafe { import.definition.as_ref() };
1045 let ret = unsafe { memory32_atomic_check64(memory, dst, val) };
1051
1052 if let Ok(mut ret) = ret {
1053 if ret == 0 {
1054 let memory = self.get_vmmemory_mut(memory_index);
1055 ret = unsafe { Self::memory_wait(memory, dst, ExpectedValue::U64(val), timeout)? };
1057 }
1058 Ok(ret)
1059 } else {
1060 ret
1061 }
1062 }
1063
1064 pub(crate) fn local_memory_notify(
1066 &mut self,
1067 memory_index: LocalMemoryIndex,
1068 dst: u32,
1069 count: u32,
1070 ) -> Result<u32, Trap> {
1071 let memory = self.memory(memory_index);
1072 memory32_atomic_check_notify(&memory, dst)?;
1073 let memory = self.get_local_vmmemory_mut(memory_index);
1074 Ok(memory.do_notify(dst, count))
1075 }
1076
1077 pub(crate) fn imported_memory_notify(
1079 &mut self,
1080 memory_index: MemoryIndex,
1081 dst: u32,
1082 count: u32,
1083 ) -> Result<u32, Trap> {
1084 let import = self.imported_memory(memory_index);
1085 let memory = unsafe { import.definition.as_ref() };
1086 memory32_atomic_check_notify(memory, dst)?;
1087 let memory = self.get_vmmemory_mut(memory_index);
1088 Ok(memory.do_notify(dst, count))
1089 }
1090}
1091
1092#[derive(Debug, Eq, PartialEq)]
1097pub struct VMInstance {
1098 instance_layout: Layout,
1100
1101 instance: NonNull<Instance>,
1111}
1112
1113impl Drop for VMInstance {
1117 fn drop(&mut self) {
1118 let instance_ptr = self.instance.as_ptr();
1119
1120 unsafe {
1121 instance_ptr.drop_in_place();
1123 std::alloc::dealloc(instance_ptr as *mut u8, self.instance_layout);
1125 }
1126 }
1127}
1128
1129impl VMInstance {
1130 #[allow(clippy::too_many_arguments)]
1152 pub unsafe fn new(
1153 allocator: InstanceAllocator,
1154 module: Arc<ModuleInfo>,
1155 context: &mut StoreObjects,
1156 finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
1157 finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
1158 finished_memories: BoxedSlice<LocalMemoryIndex, InternalStoreHandle<VMMemory>>,
1159 finished_tables: BoxedSlice<LocalTableIndex, InternalStoreHandle<VMTable>>,
1160 table_allocation_room: u32,
1161 finished_globals: BoxedSlice<LocalGlobalIndex, InternalStoreHandle<VMGlobal>>,
1162 tags: BoxedSlice<TagIndex, InternalStoreHandle<VMTag>>,
1163 imports: Imports,
1164 vmshared_signatures: BoxedSlice<SignatureIndex, VMSignatureHash>,
1165 ) -> Result<Self, Trap> {
1166 unsafe {
1167 let vmctx_tags = tags
1168 .values()
1169 .map(|m: &InternalStoreHandle<VMTag>| VMSharedTagIndex::new(m.index() as u32))
1170 .collect::<PrimaryMap<TagIndex, VMSharedTagIndex>>()
1171 .into_boxed_slice();
1172 let passive_data = RefCell::new(
1175 module
1176 .passive_data
1177 .iter()
1178 .map(|(&idx, bytes)| (idx, Some(Arc::clone(bytes))))
1179 .collect::<HashMap<_, _>>(),
1180 );
1181
1182 let handle = {
1183 let offsets = allocator.offsets().clone();
1184 let funcrefs = PrimaryMap::new().into_boxed_slice();
1186 let imported_funcrefs = PrimaryMap::new().into_boxed_slice();
1187 let instance = Instance {
1189 module,
1190 context,
1191 offsets,
1192 memories: finished_memories,
1193 tables: finished_tables,
1194 table_allocation_room,
1195 tags,
1196 globals: finished_globals,
1197 functions: finished_functions,
1198 function_call_trampolines: finished_function_call_trampolines,
1199 passive_elements: Default::default(),
1200 passive_data,
1201 funcrefs,
1202 imported_funcrefs,
1203 vmctx: VMContext {},
1204 };
1205
1206 let mut instance_handle = allocator.into_vminstance(instance);
1207
1208 {
1210 let instance = instance_handle.instance_mut();
1211 let vmctx_ptr = instance.vmctx_ptr();
1212 (instance.funcrefs, instance.imported_funcrefs) = build_funcrefs(
1213 &instance.module,
1214 context,
1215 &imports,
1216 &instance.functions,
1217 &vmshared_signatures,
1218 &instance.function_call_trampolines,
1219 vmctx_ptr,
1220 );
1221 for local_table_index in instance.tables.keys() {
1222 instance.sync_fixed_funcref_table(local_table_index);
1223 }
1224 }
1225
1226 instance_handle
1227 };
1228 let instance = handle.instance();
1229
1230 ptr::copy(
1231 vmctx_tags.values().as_slice().as_ptr(),
1232 instance.shared_tags_ptr(),
1233 vmctx_tags.len(),
1234 );
1235 ptr::copy(
1236 imports.functions.values().as_slice().as_ptr(),
1237 instance.imported_functions_ptr(),
1238 imports.functions.len(),
1239 );
1240 ptr::copy(
1241 imports.tables.values().as_slice().as_ptr(),
1242 instance.imported_tables_ptr(),
1243 imports.tables.len(),
1244 );
1245 ptr::copy(
1246 imports.memories.values().as_slice().as_ptr(),
1247 instance.imported_memories_ptr(),
1248 imports.memories.len(),
1249 );
1250 ptr::copy(
1251 imports.globals.values().as_slice().as_ptr(),
1252 instance.imported_globals_ptr(),
1253 imports.globals.len(),
1254 );
1255 ptr::write(
1259 instance.builtin_functions_ptr(),
1260 VMBuiltinFunctionsArray::initialized(),
1261 );
1262
1263 initialize_passive_elements(instance);
1266 initialize_globals(instance);
1267
1268 Ok(handle)
1269 }
1270 }
1271
1272 pub(crate) fn instance(&self) -> &Instance {
1274 unsafe { self.instance.as_ref() }
1275 }
1276
1277 pub(crate) fn instance_mut(&mut self) -> &mut Instance {
1279 unsafe { self.instance.as_mut() }
1280 }
1281
1282 pub unsafe fn finish_instantiation(
1288 &mut self,
1289 config: &VMConfig,
1290 trap_handler: Option<*const TrapHandlerFn<'static>>,
1291 data_initializers: &[DataInitializer<'_>],
1292 ) -> Result<(), Trap> {
1293 let instance = self.instance_mut();
1294
1295 initialize_tables(instance)?;
1297 initialize_memories(instance, data_initializers)?;
1298
1299 instance.invoke_start_function(config, trap_handler)?;
1302 Ok(())
1303 }
1304
1305 pub fn vmctx(&self) -> &VMContext {
1307 self.instance().vmctx()
1308 }
1309
1310 pub fn vmctx_ptr(&self) -> *mut VMContext {
1312 self.instance().vmctx_ptr()
1313 }
1314
1315 pub fn vmoffsets(&self) -> &VMOffsets {
1319 self.instance().offsets()
1320 }
1321
1322 pub fn module(&self) -> &Arc<ModuleInfo> {
1324 self.instance().module()
1325 }
1326
1327 pub fn module_ref(&self) -> &ModuleInfo {
1329 self.instance().module_ref()
1330 }
1331
1332 pub fn lookup(&mut self, field: &str) -> Option<VMExtern> {
1334 let export = *self.module_ref().exports.get(field)?;
1335
1336 Some(self.lookup_by_declaration(export))
1337 }
1338
1339 pub fn lookup_by_declaration(&mut self, export: ExportIndex) -> VMExtern {
1341 let instance = self.instance();
1342
1343 match export {
1344 ExportIndex::Function(index) => {
1345 let sig_index = &instance.module.functions[index];
1346 let handle = if let Some(def_index) = instance.module.local_func_index(index) {
1347 let signature = instance.module.signatures[*sig_index].clone();
1350 let vm_function = VMFunction {
1351 anyfunc: MaybeInstanceOwned::Instance(NonNull::from(
1352 &instance.funcrefs[def_index],
1353 )),
1354 signature,
1355 kind: VMFunctionKind::Static,
1360 host_data: Box::new(()),
1361 };
1362 InternalStoreHandle::new(self.instance_mut().context_mut(), vm_function)
1363 } else {
1364 let import = instance.imported_function(index);
1365 import.handle
1366 };
1367
1368 VMExtern::Function(handle)
1369 }
1370 ExportIndex::Table(index) => {
1371 let handle = if let Some(def_index) = instance.module.local_table_index(index) {
1372 instance.tables[def_index]
1373 } else {
1374 let import = instance.imported_table(index);
1375 import.handle
1376 };
1377 VMExtern::Table(handle)
1378 }
1379 ExportIndex::Memory(index) => {
1380 let handle = if let Some(def_index) = instance.module.local_memory_index(index) {
1381 instance.memories[def_index]
1382 } else {
1383 let import = instance.imported_memory(index);
1384 import.handle
1385 };
1386 VMExtern::Memory(handle)
1387 }
1388 ExportIndex::Global(index) => {
1389 let handle = if let Some(def_index) = instance.module.local_global_index(index) {
1390 instance.globals[def_index]
1391 } else {
1392 let import = instance.imported_global(index);
1393 import.handle
1394 };
1395 VMExtern::Global(handle)
1396 }
1397
1398 ExportIndex::Tag(index) => {
1399 let handle = instance.tags[index];
1400 VMExtern::Tag(handle)
1401 }
1402 }
1403 }
1404
1405 pub fn exports(&self) -> indexmap::map::Iter<'_, String, ExportIndex> {
1411 self.module().exports.iter()
1412 }
1413
1414 pub fn memory_index(&self, memory: &VMMemoryDefinition) -> LocalMemoryIndex {
1416 self.instance().memory_index(memory)
1417 }
1418
1419 pub fn memory_grow<IntoPages>(
1424 &mut self,
1425 memory_index: LocalMemoryIndex,
1426 delta: IntoPages,
1427 ) -> Result<Pages, MemoryError>
1428 where
1429 IntoPages: Into<Pages>,
1430 {
1431 self.instance_mut().memory_grow(memory_index, delta)
1432 }
1433
1434 pub fn table_index(&self, table: &VMTableDefinition) -> LocalTableIndex {
1436 self.instance().table_index(table)
1437 }
1438
1439 pub fn table_grow(
1444 &mut self,
1445 table_index: LocalTableIndex,
1446 delta: u32,
1447 init_value: TableElement,
1448 ) -> Option<u32> {
1449 self.instance_mut()
1450 .table_grow(table_index, delta, init_value)
1451 }
1452
1453 pub fn table_get(&self, table_index: LocalTableIndex, index: u32) -> Option<TableElement> {
1457 self.instance().table_get(table_index, index)
1458 }
1459
1460 pub fn table_set(
1464 &mut self,
1465 table_index: LocalTableIndex,
1466 index: u32,
1467 val: TableElement,
1468 ) -> Result<(), Trap> {
1469 self.instance_mut().table_set(table_index, index, val)
1470 }
1471
1472 pub fn get_local_table(&mut self, index: LocalTableIndex) -> &mut VMTable {
1474 self.instance_mut().get_local_table(index)
1475 }
1476}
1477
1478#[allow(clippy::mut_from_ref)]
1479#[allow(dead_code)]
1480unsafe fn get_memory_slice<'instance>(
1482 init: &DataInitializer<'_>,
1483 instance: &'instance Instance,
1484) -> &'instance mut [u8] {
1485 unsafe {
1486 let memory = if let Some(local_memory_index) = instance
1487 .module
1488 .local_memory_index(init.location.memory_index)
1489 {
1490 instance.memory(local_memory_index)
1491 } else {
1492 let import = instance.imported_memory(init.location.memory_index);
1493 *import.definition.as_ref()
1494 };
1495 slice::from_raw_parts_mut(memory.base, memory.current_length)
1496 }
1497}
1498
1499fn get_global(index: GlobalIndex, instance: &Instance) -> RawValue {
1500 unsafe {
1501 if let Some(local_global_index) = instance.module.local_global_index(index) {
1502 instance.global(local_global_index).val
1503 } else {
1504 instance.imported_global(index).definition.as_ref().val
1505 }
1506 }
1507}
1508
1509enum EvaluatedInitExpr {
1510 I32(i32),
1511 I64(i64),
1512}
1513
1514fn eval_init_expr(expr: &InitExpr, instance: &Instance) -> EvaluatedInitExpr {
1515 if expr
1516 .ops()
1517 .first()
1518 .expect("missing expression")
1519 .is_32bit_expression()
1520 {
1521 let mut stack = Vec::with_capacity(expr.ops().len());
1522 for op in expr.ops() {
1523 match *op {
1524 InitExprOp::I32Const(value) => stack.push(value),
1525 InitExprOp::GlobalGetI32(global) => {
1526 stack.push(unsafe { get_global(global, instance).i32 })
1527 }
1528 InitExprOp::I32Add => {
1529 let rhs = stack.pop().expect("invalid init expr stack for i32.add");
1530 let lhs = stack.pop().expect("invalid init expr stack for i32.add");
1531 stack.push(lhs.wrapping_add(rhs));
1532 }
1533 InitExprOp::I32Sub => {
1534 let rhs = stack.pop().expect("invalid init expr stack for i32.sub");
1535 let lhs = stack.pop().expect("invalid init expr stack for i32.sub");
1536 stack.push(lhs.wrapping_sub(rhs));
1537 }
1538 InitExprOp::I32Mul => {
1539 let rhs = stack.pop().expect("invalid init expr stack for i32.mul");
1540 let lhs = stack.pop().expect("invalid init expr stack for i32.mul");
1541 stack.push(lhs.wrapping_mul(rhs));
1542 }
1543 _ => {
1544 panic!("unexpected init expr statement: {op:?}");
1545 }
1546 }
1547 }
1548 EvaluatedInitExpr::I32(
1549 stack
1550 .into_iter()
1551 .exactly_one()
1552 .expect("invalid init expr stack shape"),
1553 )
1554 } else {
1555 let mut stack = Vec::with_capacity(expr.ops().len());
1556 for op in expr.ops() {
1557 match *op {
1558 InitExprOp::I64Const(value) => stack.push(value),
1559 InitExprOp::GlobalGetI64(global) => {
1560 stack.push(unsafe { get_global(global, instance).i64 })
1561 }
1562 InitExprOp::I64Add => {
1563 let rhs = stack.pop().expect("invalid init expr stack for i64.add");
1564 let lhs = stack.pop().expect("invalid init expr stack for i64.add");
1565 stack.push(lhs.wrapping_add(rhs));
1566 }
1567 InitExprOp::I64Sub => {
1568 let rhs = stack.pop().expect("invalid init expr stack for i64.sub");
1569 let lhs = stack.pop().expect("invalid init expr stack for i64.sub");
1570 stack.push(lhs.wrapping_sub(rhs));
1571 }
1572 InitExprOp::I64Mul => {
1573 let rhs = stack.pop().expect("invalid init expr stack for i64.mul");
1574 let lhs = stack.pop().expect("invalid init expr stack for i64.mul");
1575 stack.push(lhs.wrapping_mul(rhs));
1576 }
1577 _ => {
1578 panic!("unexpected init expr statement: {op:?}");
1579 }
1580 }
1581 }
1582 EvaluatedInitExpr::I64(
1583 stack
1584 .into_iter()
1585 .exactly_one()
1586 .expect("invalid init expr stack shape"),
1587 )
1588 }
1589}
1590
1591fn initialize_tables(instance: &mut Instance) -> Result<(), Trap> {
1593 let module = Arc::clone(&instance.module);
1594 for init in &module.table_initializers {
1595 let EvaluatedInitExpr::I32(start) = eval_init_expr(&init.offset_expr, instance) else {
1596 panic!("unexpected expression type, expected i32");
1597 };
1598 if start < 0 {
1599 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
1600 }
1601 let start = start as usize;
1602 let table = instance.get_table_handle(init.table_index);
1603 let table = unsafe { table.get_mut(&mut *instance.context) };
1604
1605 if start
1606 .checked_add(init.elements.len())
1607 .is_none_or(|end| end > table.size() as usize)
1608 {
1609 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
1610 }
1611
1612 if let wasmer_types::Type::FuncRef = table.ty().ty {
1613 for (i, func_idx) in init.elements.iter().enumerate() {
1614 let anyfunc = instance.func_ref(*func_idx);
1615 table
1616 .set_with_construction(
1617 u32::try_from(start + i).unwrap(),
1618 TableElement::FuncRef(anyfunc),
1619 true,
1620 )
1621 .unwrap();
1622 }
1623 } else {
1624 for i in 0..init.elements.len() {
1625 table
1626 .set_with_construction(
1627 u32::try_from(start + i).unwrap(),
1628 TableElement::ExternRef(None),
1629 true,
1630 )
1631 .unwrap();
1632 }
1633 }
1634
1635 instance.sync_fixed_funcref_table_by_index(init.table_index);
1636 }
1637
1638 Ok(())
1639}
1640
1641fn initialize_passive_elements(instance: &Instance) {
1645 let mut passive_elements = instance.passive_elements.borrow_mut();
1646 debug_assert!(
1647 passive_elements.is_empty(),
1648 "should only be called once, at initialization time"
1649 );
1650
1651 passive_elements.extend(instance.module.passive_elements.iter().filter_map(
1652 |(&idx, segments)| -> Option<(ElemIndex, Box<[Option<VMFuncRef>]>)> {
1653 if segments.is_empty() {
1654 None
1655 } else {
1656 Some((
1657 idx,
1658 segments
1659 .iter()
1660 .map(|s| instance.func_ref(*s))
1661 .collect::<Box<[Option<VMFuncRef>]>>(),
1662 ))
1663 }
1664 },
1665 ));
1666}
1667
1668fn initialize_memories(
1670 instance: &mut Instance,
1671 data_initializers: &[DataInitializer<'_>],
1672) -> Result<(), Trap> {
1673 for init in data_initializers {
1674 let memory = instance.get_vmmemory(init.location.memory_index);
1675
1676 let EvaluatedInitExpr::I32(start) = eval_init_expr(&init.location.offset_expr, instance)
1677 else {
1678 panic!("unexpected expression type, expected i32");
1679 };
1680 if start < 0 {
1681 return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
1682 }
1683 let start = start as usize;
1684 unsafe {
1685 let current_length = memory.vmmemory().as_ref().current_length;
1686 if start
1687 .checked_add(init.data.len())
1688 .is_none_or(|end| end > current_length)
1689 {
1690 return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
1691 }
1692 memory.initialize_with_data(start, init.data)?;
1693 }
1694 }
1695
1696 Ok(())
1697}
1698
1699fn initialize_globals(instance: &Instance) {
1700 let module = Arc::clone(&instance.module);
1701 for (index, initializer) in module.global_initializers.iter() {
1702 unsafe {
1703 let to = instance.global_ptr(index).as_ptr();
1704 match initializer {
1705 GlobalInit::I32Const(x) => (*to).val.i32 = *x,
1706 GlobalInit::I64Const(x) => (*to).val.i64 = *x,
1707 GlobalInit::F32Const(x) => (*to).val.f32 = *x,
1708 GlobalInit::F64Const(x) => (*to).val.f64 = *x,
1709 GlobalInit::V128Const(x) => (*to).val.bytes = *x.bytes(),
1710 GlobalInit::GetGlobal(x) => {
1711 let from: VMGlobalDefinition =
1712 if let Some(def_x) = module.local_global_index(*x) {
1713 instance.global(def_x)
1714 } else {
1715 instance.imported_global(*x).definition.as_ref().clone()
1716 };
1717 *to = from;
1718 }
1719 GlobalInit::RefNullConst => (*to).val.funcref = 0,
1720 GlobalInit::RefFunc(func_idx) => {
1721 let funcref = instance.func_ref(*func_idx).unwrap();
1722 (*to).val = funcref.into_raw();
1723 }
1724 GlobalInit::Expr(expr) => match eval_init_expr(expr, instance) {
1725 EvaluatedInitExpr::I32(value) => (*to).val.i32 = value,
1726 EvaluatedInitExpr::I64(value) => (*to).val.i64 = value,
1727 },
1728 }
1729 }
1730 }
1731}
1732
1733fn anyfunc_from_funcref(funcref: Option<VMFuncRef>) -> VMCallerCheckedAnyfunc {
1734 match funcref {
1735 Some(funcref) => unsafe { *funcref.0.as_ptr() },
1736 None => VMCallerCheckedAnyfunc::null(),
1737 }
1738}
1739
1740fn build_funcrefs(
1743 module_info: &ModuleInfo,
1744 ctx: &StoreObjects,
1745 imports: &Imports,
1746 finished_functions: &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
1747 vmshared_signatures: &BoxedSlice<SignatureIndex, VMSignatureHash>,
1748 function_call_trampolines: &BoxedSlice<SignatureIndex, VMTrampoline>,
1749 vmctx_ptr: *mut VMContext,
1750) -> (
1751 BoxedSlice<LocalFunctionIndex, VMCallerCheckedAnyfunc>,
1752 BoxedSlice<FunctionIndex, NonNull<VMCallerCheckedAnyfunc>>,
1753) {
1754 let mut func_refs =
1755 PrimaryMap::with_capacity(module_info.functions.len() - module_info.num_imported_functions);
1756 let mut imported_func_refs = PrimaryMap::with_capacity(module_info.num_imported_functions);
1757
1758 for import in imports.functions.values() {
1760 imported_func_refs.push(import.handle.get(ctx).anyfunc.as_ptr());
1761 }
1762
1763 for (local_index, func_ptr) in finished_functions.iter() {
1765 let index = module_info.func_index(local_index);
1766 let sig_index = module_info.functions[index];
1767 let type_signature_hash = vmshared_signatures[sig_index];
1768 let call_trampoline = function_call_trampolines[sig_index];
1769 let anyfunc = VMCallerCheckedAnyfunc {
1770 func_ptr: func_ptr.0,
1771 type_signature_hash,
1772 vmctx: VMFunctionContext { vmctx: vmctx_ptr },
1773 call_trampoline,
1774 };
1775 func_refs.push(anyfunc);
1776 }
1777 (
1778 func_refs.into_boxed_slice(),
1779 imported_func_refs.into_boxed_slice(),
1780 )
1781}