1use crate::{Engine, ImportError, LinkError};
5use more_asserts::assert_ge;
6use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap};
7use wasmer_types::{ExternType, FunctionIndex, ImportCounts, MemoryType, TableType};
8
9use wasmer_vm::{
10 Export, ExportFunctionMetadata, FunctionBodyPtr, ImportFunctionEnv, Imports, MemoryStyle,
11 Resolver, VMFunctionBody, VMFunctionEnvironment, VMFunctionImport, VMFunctionKind,
12 VMGlobalImport, VMImport, VMImportType, VMMemoryImport, VMTableImport,
13};
14
15fn is_compatible_table(ex: &TableType, im: &TableType) -> bool {
16 (ex.ty == wasmer_types::Type::FuncRef || ex.ty == im.ty)
17 && im.minimum <= ex.minimum
18 && (im.maximum.is_none()
19 || (!ex.maximum.is_none() && im.maximum.unwrap() >= ex.maximum.unwrap()))
20}
21
22fn is_compatible_memory(ex: &MemoryType, im: &MemoryType) -> bool {
23 im.minimum <= ex.minimum
24 && (im.maximum.is_none()
25 || (!ex.maximum.is_none() && im.maximum.unwrap() >= ex.maximum.unwrap()))
26 && ex.shared == im.shared
27}
28
29pub fn resolve_imports(
34 engine: &dyn Engine,
35 resolver: &dyn Resolver,
36 import_counts: &ImportCounts,
37 imports: &[VMImport],
38 finished_dynamic_function_trampolines: &BoxedSlice<FunctionIndex, FunctionBodyPtr>,
39) -> Result<Imports, LinkError> {
40 let mut function_imports = PrimaryMap::with_capacity(import_counts.functions as _);
41 let mut host_function_env_initializers =
42 PrimaryMap::with_capacity(import_counts.functions as _);
43 let mut table_imports = PrimaryMap::with_capacity(import_counts.tables as _);
44 let mut memory_imports = PrimaryMap::with_capacity(import_counts.memories as _);
45 let mut global_imports = PrimaryMap::with_capacity(import_counts.globals as _);
46 for VMImport {
47 import_no,
48 module,
49 field,
50 ty,
51 } in imports
52 {
53 let resolved = resolver.resolve(*import_no, module, field);
54 let import_extern = || match ty {
55 &VMImportType::Table(t) => ExternType::Table(t),
56 &VMImportType::Memory(t, _) => ExternType::Memory(t),
57 &VMImportType::Global(t) => ExternType::Global(t),
58 &VMImportType::Function {
59 sig,
60 static_trampoline: _,
61 } => ExternType::Function(
62 engine
63 .lookup_signature(sig)
64 .expect("VMSharedSignatureIndex is not valid?"),
65 ),
66 };
67 let resolved = match resolved {
68 Some(r) => r,
69 None => {
70 return Err(LinkError::Import(
71 module.to_string(),
72 field.to_string(),
73 ImportError::UnknownImport(import_extern()),
74 ));
75 }
76 };
77 let export_extern = || match resolved {
78 Export::Function(ref f) => ExternType::Function(
79 engine
80 .lookup_signature(f.vm_function.signature)
81 .expect("VMSharedSignatureIndex not registered with engine (wrong engine?)")
82 .clone(),
83 ),
84 Export::Table(ref t) => ExternType::Table(*t.ty()),
85 Export::Memory(ref m) => ExternType::Memory(m.ty()),
86 Export::Global(ref g) => {
87 let global = g.from.ty();
88 ExternType::Global(*global)
89 }
90 };
91 match (&resolved, ty) {
92 (
93 Export::Function(ex),
94 VMImportType::Function {
95 sig,
96 static_trampoline,
97 },
98 ) if ex.vm_function.signature == *sig => {
99 let address = match ex.vm_function.kind {
100 VMFunctionKind::Dynamic => {
101 let index = FunctionIndex::new(function_imports.len());
105 finished_dynamic_function_trampolines[index].0 as *mut VMFunctionBody as _
106
107 }
110 VMFunctionKind::Static => ex.vm_function.address,
111 };
112
113 let env = if let Some(ExportFunctionMetadata {
115 host_env_clone_fn: clone,
116 ..
117 }) = ex.metadata.as_deref()
118 {
119 unsafe {
123 assert!(!ex.vm_function.vmctx.host_env.is_null());
124 (clone)(ex.vm_function.vmctx.host_env)
125 }
126 } else {
127 unsafe { ex.vm_function.vmctx.host_env }
131 };
132
133 let trampoline = if let Some(t) = ex.vm_function.call_trampoline {
134 Some(t)
135 } else if let VMFunctionKind::Static = ex.vm_function.kind {
136 Some(*static_trampoline)
138 } else {
139 None
141 };
142
143 function_imports.push(VMFunctionImport {
144 body: FunctionBodyPtr(address),
145 signature: *sig,
146 environment: VMFunctionEnvironment { host_env: env },
147 trampoline,
148 });
149
150 let initializer = ex
151 .metadata
152 .as_ref()
153 .and_then(|m| m.import_init_function_ptr);
154 let clone = ex.metadata.as_ref().map(|m| m.host_env_clone_fn);
155 let destructor = ex.metadata.as_ref().map(|m| m.host_env_drop_fn);
156 let import_function_env =
157 if let (Some(clone), Some(destructor)) = (clone, destructor) {
158 ImportFunctionEnv::Env {
159 env,
160 clone,
161 initializer,
162 destructor,
163 }
164 } else {
165 ImportFunctionEnv::NoEnv
166 };
167
168 host_function_env_initializers.push(import_function_env);
169 }
170 (Export::Table(ex), VMImportType::Table(im)) if is_compatible_table(ex.ty(), im) => {
171 let import_table_ty = ex.from.ty();
172 if import_table_ty.ty != im.ty {
173 return Err(LinkError::Import(
174 module.to_string(),
175 field.to_string(),
176 ImportError::IncompatibleType(import_extern(), export_extern()),
177 ));
178 }
179 table_imports.push(VMTableImport {
180 definition: ex.from.vmtable(),
181 from: ex.from.clone(),
182 });
183 }
184 (Export::Memory(ex), VMImportType::Memory(im, import_memory_style))
185 if is_compatible_memory(&ex.ty(), im) =>
186 {
187 let export_memory_style = ex.style();
190 if let (
191 MemoryStyle::Static { bound, .. },
192 MemoryStyle::Static {
193 bound: import_bound,
194 ..
195 },
196 ) = (export_memory_style.clone(), &import_memory_style)
197 {
198 assert_ge!(bound, *import_bound);
199 }
200 assert_ge!(
201 export_memory_style.offset_guard_size(),
202 import_memory_style.offset_guard_size()
203 );
204 memory_imports.push(VMMemoryImport {
205 definition: ex.from.vmmemory(),
206 from: ex.from.clone(),
207 });
208 }
209
210 (Export::Global(ex), VMImportType::Global(im)) if ex.from.ty() == im => {
211 global_imports.push(VMGlobalImport {
212 definition: ex.from.vmglobal(),
213 from: ex.from.clone(),
214 });
215 }
216 _ => {
217 return Err(LinkError::Import(
218 module.to_string(),
219 field.to_string(),
220 ImportError::IncompatibleType(import_extern(), export_extern()),
221 ));
222 }
223 }
224 }
225 Ok(Imports::new(
226 function_imports,
227 host_function_env_initializers,
228 table_imports,
229 memory_imports,
230 global_imports,
231 ))
232}