1use crate::{Export, ExportFunctionMetadata, ImportError, LinkError};
5use more_asserts::assert_ge;
6use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap};
7use wasmer_types::{ExternType, FunctionIndex, ImportIndex, MemoryIndex, ModuleInfo, TableIndex};
8
9use wasmer_vm::{
10 FunctionBodyPtr, ImportFunctionEnv, Imports, MemoryStyle, TableStyle, VMFunctionBody,
11 VMFunctionEnvironment, VMFunctionImport, VMFunctionKind, VMGlobalImport, VMMemoryImport,
12 VMTableImport,
13};
14
15pub trait Resolver {
17 fn resolve(&self, _index: u32, module: &str, field: &str) -> Option<Export>;
37}
38
39pub trait NamedResolver {
45 fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export>;
50}
51
52impl<T: NamedResolver> Resolver for T {
54 fn resolve(&self, _index: u32, module: &str, field: &str) -> Option<Export> {
57 self.resolve_by_name(module, field)
58 }
59}
60
61impl<T: NamedResolver> NamedResolver for &T {
62 fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
63 (**self).resolve_by_name(module, field)
64 }
65}
66
67impl NamedResolver for Box<dyn NamedResolver + Send + Sync> {
68 fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
69 (**self).resolve_by_name(module, field)
70 }
71}
72
73impl NamedResolver for () {
74 fn resolve_by_name(&self, _module: &str, _field: &str) -> Option<Export> {
76 None
77 }
78}
79
80pub struct NullResolver {}
82
83impl Resolver for NullResolver {
84 fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Option<Export> {
85 None
86 }
87}
88
89fn get_extern_from_import(module: &ModuleInfo, import_index: &ImportIndex) -> ExternType {
91 match import_index {
92 ImportIndex::Function(index) => {
93 let func = module.signatures[module.functions[*index]].clone();
94 ExternType::Function(func)
95 }
96 ImportIndex::Table(index) => {
97 let table = module.tables[*index];
98 ExternType::Table(table)
99 }
100 ImportIndex::Memory(index) => {
101 let memory = module.memories[*index];
102 ExternType::Memory(memory)
103 }
104 ImportIndex::Global(index) => {
105 let global = module.globals[*index];
106 ExternType::Global(global)
107 }
108 }
109}
110
111fn get_extern_from_export(_module: &ModuleInfo, export: &Export) -> ExternType {
113 match export {
114 Export::Function(ref f) => ExternType::Function(f.vm_function.signature.clone()),
115 Export::Table(ref t) => ExternType::Table(*t.ty()),
116 Export::Memory(ref m) => ExternType::Memory(m.ty()),
117 Export::Global(ref g) => {
118 let global = g.from.ty();
119 ExternType::Global(*global)
120 }
121 }
122}
123
124pub fn resolve_imports(
129 module: &ModuleInfo,
130 resolver: &dyn Resolver,
131 finished_dynamic_function_trampolines: &BoxedSlice<FunctionIndex, FunctionBodyPtr>,
132 memory_styles: &PrimaryMap<MemoryIndex, MemoryStyle>,
133 _table_styles: &PrimaryMap<TableIndex, TableStyle>,
134) -> Result<Imports, LinkError> {
135 let mut function_imports = PrimaryMap::with_capacity(module.num_imported_functions);
136 let mut host_function_env_initializers =
137 PrimaryMap::with_capacity(module.num_imported_functions);
138 let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables);
139 let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories);
140 let mut global_imports = PrimaryMap::with_capacity(module.num_imported_globals);
141
142 for ((module_name, field, import_idx), import_index) in module.imports.iter() {
143 let resolved = resolver.resolve(*import_idx, module_name, field);
144 let import_extern = get_extern_from_import(module, import_index);
145 let resolved = match resolved {
146 None => {
147 return Err(LinkError::Import(
148 module_name.to_string(),
149 field.to_string(),
150 ImportError::UnknownImport(import_extern),
151 ));
152 }
153 Some(r) => r,
154 };
155 let export_extern = get_extern_from_export(module, &resolved);
156 if !export_extern.is_compatible_with(&import_extern) {
157 return Err(LinkError::Import(
158 module_name.to_string(),
159 field.to_string(),
160 ImportError::IncompatibleType(import_extern, export_extern),
161 ));
162 }
163 match resolved {
164 Export::Function(ref f) => {
165 let address = match f.vm_function.kind {
166 VMFunctionKind::Dynamic => {
167 let index = FunctionIndex::new(function_imports.len());
171 finished_dynamic_function_trampolines[index].0 as *mut VMFunctionBody as _
172
173 }
176 VMFunctionKind::Static => f.vm_function.address,
177 };
178
179 let env = if let Some(ExportFunctionMetadata {
181 host_env_clone_fn: clone,
182 ..
183 }) = f.metadata.as_deref()
184 {
185 unsafe {
189 assert!(!f.vm_function.vmctx.host_env.is_null());
190 (clone)(f.vm_function.vmctx.host_env)
191 }
192 } else {
193 unsafe { f.vm_function.vmctx.host_env }
197 };
198
199 function_imports.push(VMFunctionImport {
200 body: address,
201 environment: VMFunctionEnvironment { host_env: env },
202 });
203
204 let initializer = f.metadata.as_ref().and_then(|m| m.import_init_function_ptr);
205 let clone = f.metadata.as_ref().map(|m| m.host_env_clone_fn);
206 let destructor = f.metadata.as_ref().map(|m| m.host_env_drop_fn);
207 let import_function_env =
208 if let (Some(clone), Some(destructor)) = (clone, destructor) {
209 ImportFunctionEnv::Env {
210 env,
211 clone,
212 initializer,
213 destructor,
214 }
215 } else {
216 ImportFunctionEnv::NoEnv
217 };
218
219 host_function_env_initializers.push(import_function_env);
220 }
221 Export::Table(ref t) => match import_index {
222 ImportIndex::Table(index) => {
223 let import_table_ty = t.from.ty();
224 let expected_table_ty = &module.tables[*index];
225 if import_table_ty.ty != expected_table_ty.ty {
226 return Err(LinkError::Import(
227 module_name.to_string(),
228 field.to_string(),
229 ImportError::IncompatibleType(import_extern, export_extern),
230 ));
231 }
232
233 table_imports.push(VMTableImport {
234 definition: t.from.vmtable(),
235 from: t.from.clone(),
236 });
237 }
238 _ => {
239 unreachable!("Table resolution did not match");
240 }
241 },
242 Export::Memory(ref m) => {
243 match import_index {
244 ImportIndex::Memory(index) => {
245 let export_memory_style = m.style();
248 let import_memory_style = &memory_styles[*index];
249 if let (
250 MemoryStyle::Static { bound, .. },
251 MemoryStyle::Static {
252 bound: import_bound,
253 ..
254 },
255 ) = (export_memory_style.clone(), &import_memory_style)
256 {
257 assert_ge!(bound, *import_bound);
258 }
259 assert_ge!(
260 export_memory_style.offset_guard_size(),
261 import_memory_style.offset_guard_size()
262 );
263 }
264 _ => {
265 panic!("Memory resolution didn't matched");
268 }
269 }
270
271 memory_imports.push(VMMemoryImport {
272 definition: m.from.vmmemory(),
273 from: m.from.clone(),
274 });
275 }
276
277 Export::Global(ref g) => {
278 global_imports.push(VMGlobalImport {
279 definition: g.from.vmglobal(),
280 from: g.from.clone(),
281 });
282 }
283 }
284 }
285
286 Ok(Imports::new(
287 function_imports,
288 host_function_env_initializers,
289 table_imports,
290 memory_imports,
291 global_imports,
292 ))
293}
294
295pub struct NamedResolverChain<A: NamedResolver + Send + Sync, B: NamedResolver + Send + Sync> {
297 a: A,
298 b: B,
299}
300
301pub trait ChainableNamedResolver: NamedResolver + Sized + Send + Sync {
314 fn chain_front<U>(self, other: U) -> NamedResolverChain<U, Self>
329 where
330 U: NamedResolver + Send + Sync,
331 {
332 NamedResolverChain { a: other, b: self }
333 }
334
335 fn chain_back<U>(self, other: U) -> NamedResolverChain<Self, U>
350 where
351 U: NamedResolver + Send + Sync,
352 {
353 NamedResolverChain { a: self, b: other }
354 }
355}
356
357impl<T: NamedResolver + Send + Sync> ChainableNamedResolver for T {}
359
360impl<A, B> NamedResolver for NamedResolverChain<A, B>
361where
362 A: NamedResolver + Send + Sync,
363 B: NamedResolver + Send + Sync,
364{
365 fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
366 self.a
367 .resolve_by_name(module, field)
368 .or_else(|| self.b.resolve_by_name(module, field))
369 }
370}
371
372impl<A, B> Clone for NamedResolverChain<A, B>
373where
374 A: NamedResolver + Clone + Send + Sync,
375 B: NamedResolver + Clone + Send + Sync,
376{
377 fn clone(&self) -> Self {
378 Self {
379 a: self.a.clone(),
380 b: self.b.clone(),
381 }
382 }
383}