use super::{
errors::{MemoryError, TableError},
AsContextMut,
Error,
Extern,
InstancePre,
Module,
};
use crate::{
module::{ImportName, ModuleImport, ModuleImportType},
FuncType,
GlobalType,
};
use alloc::{
collections::{btree_map::Entry, BTreeMap},
sync::Arc,
vec::Vec,
};
use core::{
fmt,
fmt::{Debug, Display},
marker::PhantomData,
num::NonZeroUsize,
ops::Deref,
};
#[derive(Debug)]
pub enum LinkerError {
DuplicateDefinition {
import_name: ImportName,
import_item: Extern,
},
CannotFindDefinitionForImport {
name: ImportName,
item_type: ModuleImportType,
},
FuncTypeMismatch {
name: ImportName,
expected: FuncType,
actual: FuncType,
},
Table(TableError),
Memory(MemoryError),
GlobalTypeMismatch {
name: ImportName,
expected: GlobalType,
actual: GlobalType,
},
}
impl LinkerError {
pub fn cannot_find_definition_of_import(import: &ModuleImport) -> Self {
Self::CannotFindDefinitionForImport {
name: import.name().clone(),
item_type: import.item_type().clone(),
}
}
}
impl From<TableError> for LinkerError {
fn from(error: TableError) -> Self {
Self::Table(error)
}
}
impl From<MemoryError> for LinkerError {
fn from(error: MemoryError) -> Self {
Self::Memory(error)
}
}
#[cfg(feature = "std")]
impl std::error::Error for LinkerError {}
impl Display for LinkerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::DuplicateDefinition {
import_name,
import_item,
} => {
write!(
f,
"encountered duplicate definition `{}` of {:?}",
import_name, import_item
)
}
Self::CannotFindDefinitionForImport { name, item_type } => {
write!(
f,
"cannot find definition for import {}: {:?}",
name, item_type
)
}
Self::FuncTypeMismatch {
name,
expected,
actual,
} => {
write!(
f,
"function type mismatch for import {}: expected {:?} but found {:?}",
name, expected, actual
)
}
Self::GlobalTypeMismatch {
name,
expected,
actual,
} => {
write!(
f,
"global variable type mismatch for import {}: expected {:?} but found {:?}",
name, expected, actual
)
}
Self::Table(error) => Display::fmt(error, f),
Self::Memory(error) => Display::fmt(error, f),
}
}
}
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
#[repr(transparent)]
pub struct Symbol(NonZeroUsize);
impl Symbol {
pub fn from_usize(value: usize) -> Self {
NonZeroUsize::new(value.wrapping_add(1))
.map(Symbol)
.expect("encountered invalid symbol value")
}
pub fn into_usize(self) -> usize {
self.0.get().wrapping_sub(1)
}
}
#[derive(Debug, Default, Clone)]
pub struct StringInterner {
string2idx: BTreeMap<Arc<str>, Symbol>,
strings: Vec<Arc<str>>,
}
impl StringInterner {
fn next_symbol(&self) -> Symbol {
Symbol::from_usize(self.strings.len())
}
pub fn get_or_intern(&mut self, string: &str) -> Symbol {
match self.string2idx.get(string) {
Some(symbol) => *symbol,
None => {
let symbol = self.next_symbol();
let rc_string: Arc<str> = Arc::from(string);
self.string2idx.insert(rc_string.clone(), symbol);
self.strings.push(rc_string);
symbol
}
}
}
pub fn get(&self, string: &str) -> Option<Symbol> {
self.string2idx.get(string).copied()
}
pub fn resolve(&self, symbol: Symbol) -> Option<&str> {
self.strings.get(symbol.into_usize()).map(Deref::deref)
}
}
#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
struct ImportKey {
module: Symbol,
name: Option<Symbol>,
}
pub struct Linker<T> {
strings: StringInterner,
definitions: BTreeMap<ImportKey, Extern>,
externals: Vec<Extern>,
_marker: PhantomData<fn() -> T>,
}
impl<T> Debug for Linker<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Linker")
.field("strings", &self.strings)
.field("definitions", &self.definitions)
.finish()
}
}
impl<T> Clone for Linker<T> {
fn clone(&self) -> Linker<T> {
Self {
strings: self.strings.clone(),
definitions: self.definitions.clone(),
externals: Vec::new(),
_marker: self._marker,
}
}
}
impl<T> Default for Linker<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Linker<T> {
pub fn new() -> Self {
Self {
strings: StringInterner::default(),
definitions: BTreeMap::default(),
externals: Vec::new(),
_marker: PhantomData,
}
}
pub fn define(
&mut self,
module: &str,
name: &str,
item: impl Into<Extern>,
) -> Result<&mut Self, LinkerError> {
let key = self.import_key(module, Some(name));
self.insert(key, item.into())?;
Ok(self)
}
fn import_key(&mut self, module: &str, name: Option<&str>) -> ImportKey {
ImportKey {
module: self.strings.get_or_intern(module),
name: name.map(|name| self.strings.get_or_intern(name)),
}
}
fn resolve_import_key(&self, key: ImportKey) -> Option<(&str, Option<&str>)> {
let module_name = self.strings.resolve(key.module)?;
let item_name = if let Some(item_symbol) = key.name {
Some(self.strings.resolve(item_symbol)?)
} else {
None
};
Some((module_name, item_name))
}
fn insert(&mut self, key: ImportKey, item: Extern) -> Result<(), LinkerError> {
match self.definitions.entry(key) {
Entry::Occupied(_) => {
let (module_name, field_name) = self.resolve_import_key(key).unwrap_or_else(|| {
panic!("encountered missing import names for key {:?}", key)
});
let import_name = ImportName::new(module_name, field_name);
return Err(LinkerError::DuplicateDefinition {
import_name,
import_item: item,
});
}
Entry::Vacant(v) => {
v.insert(item);
}
}
Ok(())
}
pub fn resolve(&self, module: &str, name: Option<&str>) -> Option<Extern> {
let key = ImportKey {
module: self.strings.get(module)?,
name: match name {
Some(name) => Some(self.strings.get(name)?),
None => None,
},
};
self.definitions.get(&key).copied()
}
pub fn instantiate<'a>(
&mut self,
context: impl AsContextMut,
module: &'a Module,
) -> Result<InstancePre<'a>, Error> {
self.externals.clear();
for import in module.imports() {
let module_name = import.module();
let field_name = import.field();
let external = match import.item_type() {
ModuleImportType::Func(expected_func_type) => {
let func = self
.resolve(module_name, field_name)
.and_then(Extern::into_func)
.ok_or_else(|| LinkerError::cannot_find_definition_of_import(&import))?;
let actual_func_type = func.signature(&context);
if &actual_func_type != expected_func_type {
return Err(LinkerError::FuncTypeMismatch {
name: import.name().clone(),
expected: context
.as_context()
.store
.resolve_func_type(*expected_func_type),
actual: context
.as_context()
.store
.resolve_func_type(actual_func_type),
})
.map_err(Into::into);
}
Extern::Func(func)
}
ModuleImportType::Table(expected_table_type) => {
let table = self
.resolve(module_name, field_name)
.and_then(Extern::into_table)
.ok_or_else(|| LinkerError::cannot_find_definition_of_import(&import))?;
let actual_table_type = table.table_type(context.as_context());
actual_table_type.satisfies(expected_table_type)?;
Extern::Table(table)
}
ModuleImportType::Memory(expected_memory_type) => {
let memory = self
.resolve(module_name, field_name)
.and_then(Extern::into_memory)
.ok_or_else(|| LinkerError::cannot_find_definition_of_import(&import))?;
let actual_memory_type = memory.memory_type(context.as_context());
actual_memory_type.satisfies(expected_memory_type)?;
Extern::Memory(memory)
}
ModuleImportType::Global(expected_global_type) => {
let global = self
.resolve(module_name, field_name)
.and_then(Extern::into_global)
.ok_or_else(|| LinkerError::cannot_find_definition_of_import(&import))?;
let actual_global_type = global.global_type(context.as_context());
if &actual_global_type != expected_global_type {
return Err(LinkerError::GlobalTypeMismatch {
name: import.name().clone(),
expected: *expected_global_type,
actual: actual_global_type,
})
.map_err(Into::into);
}
Extern::Global(global)
}
};
self.externals.push(external);
}
module.instantiate(context, self.externals.drain(..))
}
}