1use super::{
2 errors::{MemoryError, TableError},
3 AsContextMut,
4 Error,
5 Extern,
6 InstancePre,
7 Module,
8};
9use crate::{
10 module::{ImportName, ImportType},
11 ExternType,
12 FuncType,
13 GlobalType,
14};
15use alloc::{
16 collections::{btree_map::Entry, BTreeMap},
17 sync::Arc,
18 vec::Vec,
19};
20use core::{
21 fmt,
22 fmt::{Debug, Display},
23 marker::PhantomData,
24 num::NonZeroUsize,
25 ops::Deref,
26};
27
28#[derive(Debug)]
30pub enum LinkerError {
31 DuplicateDefinition {
33 import_name: ImportName,
35 import_item: Extern,
39 },
40 CannotFindDefinitionForImport {
42 name: ImportName,
44 item_type: ExternType,
50 },
51 FuncTypeMismatch {
53 name: ImportName,
55 expected: FuncType,
57 actual: FuncType,
59 },
60 Table(TableError),
62 Memory(MemoryError),
64 GlobalTypeMismatch {
66 name: ImportName,
68 expected: GlobalType,
70 actual: GlobalType,
72 },
73}
74
75impl LinkerError {
76 pub fn cannot_find_definition_of_import(import: &ImportType) -> Self {
78 Self::CannotFindDefinitionForImport {
79 name: import.import_name().clone(),
80 item_type: import.ty().clone(),
81 }
82 }
83}
84
85impl From<TableError> for LinkerError {
86 fn from(error: TableError) -> Self {
87 Self::Table(error)
88 }
89}
90
91impl From<MemoryError> for LinkerError {
92 fn from(error: MemoryError) -> Self {
93 Self::Memory(error)
94 }
95}
96
97#[cfg(feature = "std")]
98impl std::error::Error for LinkerError {}
99
100impl Display for LinkerError {
101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102 match self {
103 Self::DuplicateDefinition {
104 import_name,
105 import_item,
106 } => {
107 write!(
108 f,
109 "encountered duplicate definition `{import_name}` of {import_item:?}",
110 )
111 }
112 Self::CannotFindDefinitionForImport { name, item_type } => {
113 write!(f, "cannot find definition for import {name}: {item_type:?}",)
114 }
115 Self::FuncTypeMismatch {
116 name,
117 expected,
118 actual,
119 } => {
120 write!(
121 f,
122 "function type mismatch for import {name}: \
123 expected {expected:?} but found {actual:?}",
124 )
125 }
126 Self::GlobalTypeMismatch {
127 name,
128 expected,
129 actual,
130 } => {
131 write!(
132 f,
133 "global variable type mismatch for import {name}: \
134 expected {expected:?} but found {actual:?}",
135 )
136 }
137 Self::Table(error) => Display::fmt(error, f),
138 Self::Memory(error) => Display::fmt(error, f),
139 }
140 }
141}
142
143#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
157#[repr(transparent)]
158pub struct Symbol(NonZeroUsize);
159
160impl Symbol {
161 pub fn from_usize(value: usize) -> Self {
167 NonZeroUsize::new(value.wrapping_add(1))
168 .map(Symbol)
169 .expect("encountered invalid symbol value")
170 }
171
172 pub fn into_usize(self) -> usize {
174 self.0.get().wrapping_sub(1)
175 }
176}
177
178#[derive(Debug, Default, Clone)]
182pub struct StringInterner {
183 string2idx: BTreeMap<Arc<str>, Symbol>,
184 strings: Vec<Arc<str>>,
185}
186
187impl StringInterner {
188 fn next_symbol(&self) -> Symbol {
190 Symbol::from_usize(self.strings.len())
191 }
192
193 pub fn get_or_intern(&mut self, string: &str) -> Symbol {
195 match self.string2idx.get(string) {
196 Some(symbol) => *symbol,
197 None => {
198 let symbol = self.next_symbol();
199 let rc_string: Arc<str> = Arc::from(string);
200 self.string2idx.insert(rc_string.clone(), symbol);
201 self.strings.push(rc_string);
202 symbol
203 }
204 }
205 }
206
207 pub fn get(&self, string: &str) -> Option<Symbol> {
209 self.string2idx.get(string).copied()
210 }
211
212 pub fn resolve(&self, symbol: Symbol) -> Option<&str> {
214 self.strings.get(symbol.into_usize()).map(Deref::deref)
215 }
216}
217
218#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
220struct ImportKey {
221 module: Symbol,
223 name: Symbol,
225}
226
227pub struct Linker<T> {
229 strings: StringInterner,
231 definitions: BTreeMap<ImportKey, Extern>,
233 marker: PhantomData<fn() -> T>,
234}
235
236impl<T> Debug for Linker<T> {
237 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
238 f.debug_struct("Linker")
239 .field("strings", &self.strings)
240 .field("definitions", &self.definitions)
241 .finish()
242 }
243}
244
245impl<T> Clone for Linker<T> {
246 fn clone(&self) -> Linker<T> {
247 Self {
248 strings: self.strings.clone(),
249 definitions: self.definitions.clone(),
250 marker: self.marker,
251 }
252 }
253}
254
255impl<T> Default for Linker<T> {
256 fn default() -> Self {
257 Self::new()
258 }
259}
260
261impl<T> Linker<T> {
262 pub fn new() -> Self {
264 Self {
265 strings: StringInterner::default(),
266 definitions: BTreeMap::default(),
267 marker: PhantomData,
268 }
269 }
270
271 pub fn define(
277 &mut self,
278 module: &str,
279 name: &str,
280 item: impl Into<Extern>,
281 ) -> Result<&mut Self, LinkerError> {
282 let key = self.import_key(module, name);
283 self.insert(key, item.into())?;
284 Ok(self)
285 }
286
287 fn import_key(&mut self, module: &str, name: &str) -> ImportKey {
289 ImportKey {
290 module: self.strings.get_or_intern(module),
291 name: self.strings.get_or_intern(name),
292 }
293 }
294
295 fn resolve_import_key(&self, key: ImportKey) -> Option<(&str, &str)> {
297 let module_name = self.strings.resolve(key.module)?;
298 let item_name = self.strings.resolve(key.name)?;
299 Some((module_name, item_name))
300 }
301
302 fn insert(&mut self, key: ImportKey, item: Extern) -> Result<(), LinkerError> {
308 match self.definitions.entry(key) {
309 Entry::Occupied(_) => {
310 let (module_name, field_name) = self
311 .resolve_import_key(key)
312 .unwrap_or_else(|| panic!("encountered missing import names for key {key:?}"));
313 let import_name = ImportName::new(module_name, field_name);
314 return Err(LinkerError::DuplicateDefinition {
315 import_name,
316 import_item: item,
317 });
318 }
319 Entry::Vacant(v) => {
320 v.insert(item);
321 }
322 }
323 Ok(())
324 }
325
326 pub fn resolve(&self, module: &str, name: &str) -> Option<Extern> {
331 let key = ImportKey {
332 module: self.strings.get(module)?,
333 name: self.strings.get(name)?,
334 };
335 self.definitions.get(&key).copied()
336 }
337
338 pub fn instantiate(
345 &self,
346 mut context: impl AsContextMut,
347 module: &Module,
348 ) -> Result<InstancePre, Error> {
349 let externals = module
350 .imports()
351 .map(|import| self.process_import(&mut context, import))
352 .collect::<Result<Vec<Extern>, Error>>()?;
353 module.instantiate(context, externals)
354 }
355
356 fn process_import(
362 &self,
363 context: impl AsContextMut,
364 import: ImportType,
365 ) -> Result<Extern, Error> {
366 let make_err = || LinkerError::cannot_find_definition_of_import(&import);
367 let module_name = import.module();
368 let field_name = import.name();
369 let resolved = self.resolve(module_name, field_name);
370 let context = context.as_context();
371 match import.ty() {
372 ExternType::Func(expected_func_type) => {
373 let func = resolved.and_then(Extern::into_func).ok_or_else(make_err)?;
374 let actual_func_type = func.ty_dedup(&context);
375 let actual_func_type = context.store.resolve_func_type(actual_func_type);
376 if &actual_func_type != expected_func_type {
377 return Err(LinkerError::FuncTypeMismatch {
378 name: import.import_name().clone(),
379 expected: expected_func_type.clone(),
380 actual: actual_func_type,
381 })
382 .map_err(Into::into);
383 }
384 Ok(Extern::Func(func))
385 }
386 ExternType::Table(expected_table_type) => {
387 let table = resolved.and_then(Extern::into_table).ok_or_else(make_err)?;
388 let actual_table_type = table.ty(context);
389 actual_table_type.satisfies(expected_table_type)?;
390 Ok(Extern::Table(table))
391 }
392 ExternType::Memory(expected_memory_type) => {
393 let memory = resolved
394 .and_then(Extern::into_memory)
395 .ok_or_else(make_err)?;
396 let actual_memory_type = memory.ty(context);
397 actual_memory_type.satisfies(expected_memory_type)?;
398 Ok(Extern::Memory(memory))
399 }
400 ExternType::Global(expected_global_type) => {
401 let global = resolved
402 .and_then(Extern::into_global)
403 .ok_or_else(make_err)?;
404 let actual_global_type = global.ty(context);
405 if &actual_global_type != expected_global_type {
406 return Err(LinkerError::GlobalTypeMismatch {
407 name: import.import_name().clone(),
408 expected: *expected_global_type,
409 actual: actual_global_type,
410 })
411 .map_err(Into::into);
412 }
413 Ok(Extern::Global(global))
414 }
415 }
416 }
417}