1use crate::LinkError;
4use more_asserts::assert_ge;
5use wasmer_types::{
6 ExternType, FunctionIndex, ImportError, ImportIndex, MemoryIndex, ModuleInfo, TableIndex,
7 TagType,
8};
9use wasmer_types::{
10 TagIndex, TagKind,
11 entity::{BoxedSlice, EntityRef, PrimaryMap},
12};
13
14use wasmer_vm::{
15 FunctionBodyPtr, Imports, InternalStoreHandle, LinearMemory, MemoryStyle, StoreObjects,
16 TableStyle, VMExtern, VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalImport,
17 VMMemoryImport, VMTableImport, VMTag,
18};
19
20fn get_extern_from_import(module: &ModuleInfo, import_index: &ImportIndex) -> ExternType {
22 match import_index {
23 ImportIndex::Function(index) => {
24 let func = module.signatures[module.functions[*index]].clone();
25 ExternType::Function(func)
26 }
27 ImportIndex::Table(index) => {
28 let table = module.tables[*index];
29 ExternType::Table(table)
30 }
31 ImportIndex::Memory(index) => {
32 let memory = module.memories[*index];
33 ExternType::Memory(memory)
34 }
35 ImportIndex::Global(index) => {
36 let global = module.globals[*index];
37 ExternType::Global(global)
38 }
39 ImportIndex::Tag(index) => {
40 let func = module.signatures[module.tags[*index]].clone();
41 ExternType::Tag(TagType::from_fn_type(
42 wasmer_types::TagKind::Exception,
43 func,
44 ))
45 }
46 }
47}
48
49fn get_extern_type(context: &StoreObjects, extern_: &VMExtern) -> ExternType {
51 match extern_ {
52 VMExtern::Tag(f) => ExternType::Tag(wasmer_types::TagType::from_fn_type(
53 wasmer_types::TagKind::Exception,
54 f.get(context).signature.clone(),
55 )),
56 VMExtern::Function(f) => ExternType::Function(f.get(context).signature.clone()),
57 VMExtern::Table(t) => ExternType::Table(*t.get(context).ty()),
58 VMExtern::Memory(m) => ExternType::Memory(m.get(context).ty()),
59 VMExtern::Global(g) => {
60 let global = g.get(context).ty();
61 ExternType::Global(*global)
62 }
63 }
64}
65
66fn get_runtime_size(context: &StoreObjects, extern_: &VMExtern) -> Option<u32> {
67 match extern_ {
68 VMExtern::Table(t) => Some(t.get(context).get_runtime_size()),
69 VMExtern::Memory(m) => Some(m.get(context).get_runtime_size()),
70 _ => None,
71 }
72}
73
74#[allow(clippy::result_large_err)]
79pub fn resolve_imports(
80 module: &ModuleInfo,
81 imports: &[VMExtern],
82 context: &mut StoreObjects,
83 finished_dynamic_function_trampolines: &BoxedSlice<FunctionIndex, FunctionBodyPtr>,
84 memory_styles: &PrimaryMap<MemoryIndex, MemoryStyle>,
85 _table_styles: &PrimaryMap<TableIndex, TableStyle>,
86) -> Result<Imports, LinkError> {
87 let mut function_imports = PrimaryMap::with_capacity(module.num_imported_functions);
88 let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables);
89 let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories);
90 let mut global_imports = PrimaryMap::with_capacity(module.num_imported_globals);
91
92 for (import_key, import_index) in module
93 .imports
94 .iter()
95 .filter(|(_, import_index)| !matches!(import_index, ImportIndex::Tag(_)))
96 {
97 let ResolvedImport {
98 resolved,
99 import_extern,
100 extern_type,
101 } = resolve_import(module, imports, context, import_key, import_index)?;
102 match *resolved {
103 VMExtern::Function(handle) => {
104 let f = handle.get_mut(context);
105 let address = match f.kind {
106 VMFunctionKind::Dynamic => {
107 let index = FunctionIndex::new(function_imports.len());
111 let ptr = finished_dynamic_function_trampolines[index].0
112 as *mut VMFunctionBody as _;
113 unsafe { f.anyfunc.as_ptr().as_mut() }.func_ptr = ptr;
119 ptr
120 }
121 VMFunctionKind::Static => unsafe { f.anyfunc.as_ptr().as_ref().func_ptr },
122 };
123
124 function_imports.push(VMFunctionImport {
125 body: address,
126 environment: unsafe { f.anyfunc.as_ptr().as_ref().vmctx },
127 handle,
128 include_m0_param: handle.get(context).host_data.is::<()>(),
130 });
131 }
132 VMExtern::Table(handle) => {
133 let t = handle.get(context);
134 match import_index {
135 ImportIndex::Table(index) => {
136 let import_table_ty = t.ty();
137 let expected_table_ty = &module.tables[*index];
138 if import_table_ty.ty != expected_table_ty.ty {
139 return Err(LinkError::Import(
140 import_key.module.to_string(),
141 import_key.field.to_string(),
142 ImportError::IncompatibleType(import_extern, extern_type),
143 ));
144 }
145
146 table_imports.push(VMTableImport {
147 definition: t.vmtable(),
148 handle,
149 });
150 }
151 _ => {
152 unreachable!("Table resolution did not match");
153 }
154 }
155 }
156 VMExtern::Memory(handle) => {
157 let m = handle.get(context);
158 match import_index {
159 ImportIndex::Memory(index) => {
160 let export_memory_style = m.style();
163 let import_memory_style = &memory_styles[*index];
164 if matches!(import_memory_style, MemoryStyle::Static)
165 && !matches!(export_memory_style, MemoryStyle::Static)
166 {
167 return Err(LinkError::Import(
168 import_key.module.to_string(),
169 import_key.field.to_string(),
170 ImportError::MemoryError(
171 "a static memory import cannot use a dynamic allocation"
172 .to_string(),
173 ),
174 ));
175 }
176 assert_ge!(
177 export_memory_style.offset_guard_size(),
178 import_memory_style.offset_guard_size()
179 );
180 }
181 _ => {
182 panic!("Memory resolution didn't matched");
185 }
186 }
187
188 memory_imports.push(VMMemoryImport {
189 definition: m.vmmemory(),
190 handle,
191 });
192 }
193
194 VMExtern::Global(handle) => {
195 let g = handle.get(context);
196 global_imports.push(VMGlobalImport {
197 definition: g.vmglobal(),
198 handle,
199 });
200 }
201
202 VMExtern::Tag(_) => unreachable!("We already filtered tags out"),
203 }
204 }
205
206 Ok(Imports::new(
207 function_imports,
208 table_imports,
209 memory_imports,
210 global_imports,
211 ))
212}
213
214#[allow(clippy::result_large_err)]
222pub fn resolve_tags(
223 module: &ModuleInfo,
224 imports: &[VMExtern],
225 context: &mut StoreObjects,
226) -> Result<BoxedSlice<TagIndex, InternalStoreHandle<VMTag>>, LinkError> {
227 let mut tags = PrimaryMap::with_capacity(module.tags.len());
228
229 for (import_key, import_index) in module
230 .imports
231 .iter()
232 .filter(|(_, import_index)| matches!(import_index, ImportIndex::Tag(_)))
233 {
234 let ResolvedImport {
235 resolved,
236 import_extern,
237 extern_type,
238 } = resolve_import(module, imports, context, import_key, import_index)?;
239 match *resolved {
240 VMExtern::Tag(handle) => {
241 let t = handle.get(context);
242 match import_index {
243 ImportIndex::Tag(index) => {
244 let import_tag_ty = &t.signature;
245 let expected_tag_ty = if let Some(expected_tag_ty) =
246 module.signatures.get(module.tags[*index])
247 {
248 expected_tag_ty
249 } else {
250 return Err(LinkError::Resource(format!(
251 "Could not find matching signature for tag index {index:?}"
252 )));
253 };
254 if *import_tag_ty != *expected_tag_ty {
255 return Err(LinkError::Import(
256 import_key.module.to_string(),
257 import_key.field.to_string(),
258 ImportError::IncompatibleType(import_extern, extern_type),
259 ));
260 }
261
262 tags.push(handle);
263 }
264 _ => {
265 unreachable!("Tag resolution did not match");
266 }
267 }
268 }
269 _ => unreachable!("We already filtered everything else out"),
270 }
271 }
272
273 for (tag_index, signature_index) in module.tags.iter() {
278 if module.is_imported_tag(tag_index) {
279 continue;
280 }
281 let sig_ty = if let Some(sig_ty) = module.signatures.get(*signature_index) {
282 sig_ty
283 } else {
284 return Err(LinkError::Resource(format!(
285 "Could not find matching signature for tag index {tag_index:?}"
286 )));
287 };
288 let handle =
289 InternalStoreHandle::new(context, VMTag::new(TagKind::Exception, sig_ty.clone()));
290 tags.push(handle);
291 }
292
293 Ok(tags.into_boxed_slice())
294}
295
296struct ResolvedImport<'a> {
297 resolved: &'a VMExtern,
298 import_extern: ExternType,
299 extern_type: ExternType,
300}
301
302#[allow(clippy::result_large_err)]
303fn resolve_import<'a>(
304 module: &ModuleInfo,
305 imports: &'a [VMExtern],
306 context: &mut StoreObjects,
307 import: &wasmer_types::ImportKey,
308 import_index: &ImportIndex,
309) -> Result<ResolvedImport<'a>, LinkError> {
310 let import_extern = get_extern_from_import(module, import_index);
311 let resolved = if let Some(r) = imports.get(import.import_idx as usize) {
312 r
313 } else {
314 return Err(LinkError::Import(
315 import.module.to_string(),
316 import.field.to_string(),
317 ImportError::UnknownImport(import_extern),
318 ));
319 };
320 let extern_type = get_extern_type(context, resolved);
321 let runtime_size = get_runtime_size(context, resolved);
322 if !extern_type.is_compatible_with(&import_extern, runtime_size) {
323 return Err(LinkError::Import(
324 import.module.to_string(),
325 import.field.to_string(),
326 ImportError::IncompatibleType(import_extern, extern_type),
327 ));
328 }
329 Ok(ResolvedImport {
330 resolved,
331 import_extern,
332 extern_type,
333 })
334}