1use crate::LinkError;
4use more_asserts::assert_ge;
5use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap};
6use wasmer_types::{
7 ExternType, FunctionIndex, ImportError, ImportIndex, MemoryIndex, ModuleInfo, TableIndex,
8 TagType,
9};
10
11use wasmer_vm::{
12 FunctionBodyPtr, Imports, LinearMemory, MemoryStyle, StoreObjects, TableStyle, VMExtern,
13 VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalImport, VMMemoryImport,
14 VMTableImport, VMTagImport,
15};
16
17fn get_extern_from_import(module: &ModuleInfo, import_index: &ImportIndex) -> ExternType {
19 match import_index {
20 ImportIndex::Function(index) => {
21 let func = module.signatures[module.functions[*index]].clone();
22 ExternType::Function(func)
23 }
24 ImportIndex::Table(index) => {
25 let table = module.tables[*index];
26 ExternType::Table(table)
27 }
28 ImportIndex::Memory(index) => {
29 let memory = module.memories[*index];
30 ExternType::Memory(memory)
31 }
32 ImportIndex::Global(index) => {
33 let global = module.globals[*index];
34 ExternType::Global(global)
35 }
36 ImportIndex::Tag(index) => {
37 let func = module.signatures[module.tags[*index]].clone();
38 ExternType::Tag(TagType::from_fn_type(
39 wasmer_types::TagKind::Exception,
40 func,
41 ))
42 }
43 }
44}
45
46fn get_extern_type(context: &StoreObjects, extern_: &VMExtern) -> ExternType {
48 match extern_ {
49 VMExtern::Tag(f) => ExternType::Tag(wasmer_types::TagType::from_fn_type(
50 wasmer_types::TagKind::Exception,
51 f.get(context).signature.clone(),
52 )),
53 VMExtern::Function(f) => ExternType::Function(f.get(context).signature.clone()),
54 VMExtern::Table(t) => ExternType::Table(*t.get(context).ty()),
55 VMExtern::Memory(m) => ExternType::Memory(m.get(context).ty()),
56 VMExtern::Global(g) => {
57 let global = g.get(context).ty();
58 ExternType::Global(*global)
59 }
60 }
61}
62
63fn get_runtime_size(context: &StoreObjects, extern_: &VMExtern) -> Option<u32> {
64 match extern_ {
65 VMExtern::Table(t) => Some(t.get(context).get_runtime_size()),
66 VMExtern::Memory(m) => Some(m.get(context).get_runtime_size()),
67 _ => None,
68 }
69}
70
71#[allow(clippy::result_large_err)]
76pub fn resolve_imports(
77 module: &ModuleInfo,
78 imports: &[VMExtern],
79 context: &mut StoreObjects,
80 finished_dynamic_function_trampolines: &BoxedSlice<FunctionIndex, FunctionBodyPtr>,
81 memory_styles: &PrimaryMap<MemoryIndex, MemoryStyle>,
82 _table_styles: &PrimaryMap<TableIndex, TableStyle>,
83) -> Result<Imports, LinkError> {
84 let mut function_imports = PrimaryMap::with_capacity(module.num_imported_functions);
85 let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables);
86 let mut tag_imports = PrimaryMap::with_capacity(module.num_imported_tags);
87 let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories);
88 let mut global_imports = PrimaryMap::with_capacity(module.num_imported_globals);
89
90 for (
91 wasmer_types::ImportKey {
92 module: module_name,
93 field,
94 import_idx,
95 },
96 import_index,
97 ) in module.imports.iter()
98 {
99 let import_extern = get_extern_from_import(module, import_index);
100 let resolved = if let Some(r) = imports.get(*import_idx as usize) {
101 r
102 } else {
103 return Err(LinkError::Import(
104 module_name.to_string(),
105 field.to_string(),
106 ImportError::UnknownImport(import_extern),
107 ));
108 };
109 let extern_type = get_extern_type(context, resolved);
110 let runtime_size = get_runtime_size(context, resolved);
111 if !extern_type.is_compatible_with(&import_extern, runtime_size) {
112 return Err(LinkError::Import(
113 module_name.to_string(),
114 field.to_string(),
115 ImportError::IncompatibleType(import_extern, extern_type),
116 ));
117 }
118 match *resolved {
119 VMExtern::Function(handle) => {
120 let f = handle.get_mut(context);
121 let address = match f.kind {
122 VMFunctionKind::Dynamic => {
123 let index = FunctionIndex::new(function_imports.len());
127 let ptr = finished_dynamic_function_trampolines[index].0
128 as *mut VMFunctionBody as _;
129 unsafe { f.anyfunc.as_ptr().as_mut() }.func_ptr = ptr;
135 ptr
136 }
137 VMFunctionKind::Static => unsafe { f.anyfunc.as_ptr().as_ref().func_ptr },
138 };
139
140 function_imports.push(VMFunctionImport {
141 body: address,
142 environment: unsafe { f.anyfunc.as_ptr().as_ref().vmctx },
143 handle,
144 });
145 }
146 VMExtern::Table(handle) => {
147 let t = handle.get(context);
148 match import_index {
149 ImportIndex::Table(index) => {
150 let import_table_ty = t.ty();
151 let expected_table_ty = &module.tables[*index];
152 if import_table_ty.ty != expected_table_ty.ty {
153 return Err(LinkError::Import(
154 module_name.to_string(),
155 field.to_string(),
156 ImportError::IncompatibleType(import_extern, extern_type),
157 ));
158 }
159
160 table_imports.push(VMTableImport {
161 definition: t.vmtable(),
162 handle,
163 });
164 }
165 _ => {
166 unreachable!("Table resolution did not match");
167 }
168 }
169 }
170 VMExtern::Memory(handle) => {
171 let m = handle.get(context);
172 match import_index {
173 ImportIndex::Memory(index) => {
174 let export_memory_style = m.style();
177 let import_memory_style = &memory_styles[*index];
178 if let (
179 MemoryStyle::Static { bound, .. },
180 MemoryStyle::Static {
181 bound: import_bound,
182 ..
183 },
184 ) = (export_memory_style, &import_memory_style)
185 {
186 assert_ge!(bound, *import_bound);
187 }
188 assert_ge!(
189 export_memory_style.offset_guard_size(),
190 import_memory_style.offset_guard_size()
191 );
192 }
193 _ => {
194 panic!("Memory resolution didn't matched");
197 }
198 }
199
200 memory_imports.push(VMMemoryImport {
201 definition: m.vmmemory(),
202 handle,
203 });
204 }
205
206 VMExtern::Global(handle) => {
207 let g = handle.get(context);
208 global_imports.push(VMGlobalImport {
209 definition: g.vmglobal(),
210 handle,
211 });
212 }
213 VMExtern::Tag(handle) => {
214 tag_imports.push(VMTagImport { handle });
215 }
216 }
217 }
218
219 Ok(Imports::new(
220 function_imports,
221 table_imports,
222 memory_imports,
223 tag_imports,
224 global_imports,
225 ))
226}