use crate::{
backend::RunnableModule,
cache::{Artifact, Error as CacheError},
error,
import::ImportObject,
structures::{Map, TypedIndex},
types::{
ExportDescriptor, FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit,
ImportDescriptor, ImportedFuncIndex, ImportedGlobalIndex, ImportedMemoryIndex,
ImportedTableIndex, Initializer, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex,
MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor, TableIndex,
},
Instance,
};
use crate::backend::CacheGen;
#[cfg(feature = "generate-debug-information")]
use crate::jit_debug;
use indexmap::IndexMap;
use std::collections::HashMap;
use std::sync::Arc;
#[doc(hidden)]
pub struct ModuleInner {
pub runnable_module: Arc<Box<dyn RunnableModule>>,
pub cache_gen: Box<dyn CacheGen>,
pub info: ModuleInfo,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ModuleInfo {
pub memories: Map<LocalMemoryIndex, MemoryDescriptor>,
pub globals: Map<LocalGlobalIndex, GlobalInit>,
pub tables: Map<LocalTableIndex, TableDescriptor>,
pub imported_functions: Map<ImportedFuncIndex, ImportName>,
pub imported_memories: Map<ImportedMemoryIndex, (ImportName, MemoryDescriptor)>,
pub imported_tables: Map<ImportedTableIndex, (ImportName, TableDescriptor)>,
pub imported_globals: Map<ImportedGlobalIndex, (ImportName, GlobalDescriptor)>,
pub exports: IndexMap<String, ExportIndex>,
pub data_initializers: Vec<DataInitializer>,
pub elem_initializers: Vec<TableInitializer>,
pub start_func: Option<FuncIndex>,
pub func_assoc: Map<FuncIndex, SigIndex>,
pub signatures: Map<SigIndex, FuncSig>,
pub backend: String,
pub namespace_table: StringTable<NamespaceIndex>,
pub name_table: StringTable<NameIndex>,
pub em_symbol_map: Option<HashMap<u32, String>>,
pub custom_sections: HashMap<String, Vec<Vec<u8>>>,
pub generate_debug_info: bool,
#[cfg(feature = "generate-debug-information")]
#[serde(skip)]
pub(crate) debug_info_manager: jit_debug::JitCodeDebugInfoManager,
}
impl ModuleInfo {
pub fn import_custom_sections(&mut self, wasm: &[u8]) -> crate::error::ParseResult<()> {
let mut parser = wasmparser::ModuleReader::new(wasm)?;
while !parser.eof() {
let section = parser.read()?;
if let wasmparser::SectionCode::Custom { name, kind: _ } = section.code {
let mut reader = section.get_binary_reader();
let len = reader.bytes_remaining();
let bytes = reader.read_bytes(len)?;
let data = bytes.to_vec();
let name = name.to_string();
let entry: &mut Vec<Vec<u8>> = self.custom_sections.entry(name).or_default();
entry.push(data);
}
}
Ok(())
}
}
pub struct Module {
inner: Arc<ModuleInner>,
}
impl Module {
pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
Module { inner }
}
pub fn instantiate(&self, import_object: &ImportObject) -> error::Result<Instance> {
Instance::new(Arc::clone(&self.inner), import_object)
}
pub fn cache(&self) -> Result<Artifact, CacheError> {
let (backend_metadata, code) = self.inner.cache_gen.generate_cache()?;
Ok(Artifact::from_parts(
Box::new(self.inner.info.clone()),
backend_metadata,
code,
))
}
pub fn info(&self) -> &ModuleInfo {
&self.inner.info
}
pub fn exports(&self) -> Vec<ExportDescriptor> {
self.inner.exports()
}
pub fn imports(&self) -> Vec<ImportDescriptor> {
let mut out = Vec::with_capacity(
self.inner.info.imported_functions.len()
+ self.inner.info.imported_memories.len()
+ self.inner.info.imported_tables.len()
+ self.inner.info.imported_globals.len(),
);
fn get_import_name(
info: &ModuleInfo,
&ImportName {
namespace_index,
name_index,
}: &ImportName,
) -> (String, String) {
let namespace = info.namespace_table.get(namespace_index).to_string();
let name = info.name_table.get(name_index).to_string();
(namespace, name)
}
let info = &self.inner.info;
let imported_functions = info.imported_functions.iter().map(|(idx, import_name)| {
let (namespace, name) = get_import_name(info, import_name);
let sig = info
.signatures
.get(*info.func_assoc.get(FuncIndex::new(idx.index())).unwrap())
.unwrap();
ImportDescriptor {
namespace,
name,
ty: sig.into(),
}
});
let imported_memories =
info.imported_memories
.values()
.map(|(import_name, memory_descriptor)| {
let (namespace, name) = get_import_name(info, import_name);
ImportDescriptor {
namespace,
name,
ty: memory_descriptor.into(),
}
});
let imported_tables =
info.imported_tables
.values()
.map(|(import_name, table_descriptor)| {
let (namespace, name) = get_import_name(info, import_name);
ImportDescriptor {
namespace,
name,
ty: table_descriptor.into(),
}
});
let imported_globals =
info.imported_globals
.values()
.map(|(import_name, global_descriptor)| {
let (namespace, name) = get_import_name(info, import_name);
ImportDescriptor {
namespace,
name,
ty: global_descriptor.into(),
}
});
out.extend(imported_functions);
out.extend(imported_memories);
out.extend(imported_tables);
out.extend(imported_globals);
out
}
pub fn custom_sections(&self, key: impl AsRef<str>) -> Option<&[Vec<u8>]> {
let key = key.as_ref();
self.inner.info.custom_sections.get(key).map(|v| v.as_ref())
}
}
impl Clone for Module {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
impl ModuleInner {
pub(crate) fn exports_iter(&self) -> impl Iterator<Item = ExportDescriptor> + '_ {
self.info
.exports
.iter()
.map(move |(name, &ei)| ExportDescriptor {
name,
ty: match ei {
ExportIndex::Func(f_idx) => {
let sig_idx = self.info.func_assoc[f_idx].into();
self.info.signatures[sig_idx].clone().into()
}
ExportIndex::Global(g_idx) => {
let info = &self.info;
let local_global_idx =
LocalGlobalIndex::new(g_idx.index() - info.imported_globals.len());
info.globals[local_global_idx].desc.into()
}
ExportIndex::Memory(m_idx) => {
let info = &self.info;
let local_memory_idx =
LocalMemoryIndex::new(m_idx.index() - info.imported_memories.len());
info.memories[local_memory_idx].into()
}
ExportIndex::Table(t_idx) => {
let info = &self.info;
let local_table_idx =
LocalTableIndex::new(t_idx.index() - info.imported_tables.len());
info.tables[local_table_idx].into()
}
},
})
}
pub fn exports(&self) -> Vec<ExportDescriptor> {
self.exports_iter().collect()
}
}
#[doc(hidden)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ImportName {
pub namespace_index: NamespaceIndex,
pub name_index: NameIndex,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExportIndex {
Func(FuncIndex),
Memory(MemoryIndex),
Global(GlobalIndex),
Table(TableIndex),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DataInitializer {
pub memory_index: MemoryIndex,
pub base: Initializer,
#[cfg_attr(feature = "cache", serde(with = "serde_bytes"))]
pub data: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TableInitializer {
pub table_index: TableIndex,
pub base: Initializer,
pub elements: Vec<FuncIndex>,
}
pub struct StringTableBuilder<K: TypedIndex> {
map: IndexMap<String, (K, u32, u32)>,
buffer: String,
count: u32,
}
impl<K: TypedIndex> StringTableBuilder<K> {
pub fn new() -> Self {
Self {
map: IndexMap::new(),
buffer: String::new(),
count: 0,
}
}
pub fn register<S>(&mut self, s: S) -> K
where
S: Into<String> + AsRef<str>,
{
let s_str = s.as_ref();
if self.map.contains_key(s_str) {
self.map[s_str].0
} else {
let offset = self.buffer.len();
let length = s_str.len();
let index = TypedIndex::new(self.count as _);
self.buffer.push_str(s_str);
self.map
.insert(s.into(), (index, offset as u32, length as u32));
self.count += 1;
index
}
}
pub fn finish(self) -> StringTable<K> {
let table = self
.map
.values()
.map(|(_, offset, length)| (*offset, *length))
.collect();
StringTable {
table,
buffer: self.buffer,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct StringTable<K: TypedIndex> {
table: Map<K, (u32, u32)>,
buffer: String,
}
impl<K: TypedIndex> StringTable<K> {
pub fn new() -> Self {
Self {
table: Map::new(),
buffer: String::new(),
}
}
pub fn get(&self, index: K) -> &str {
let (offset, length) = self.table[index];
let offset = offset as usize;
let length = length as usize;
&self.buffer[offset..offset + length]
}
}
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct NamespaceIndex(u32);
impl TypedIndex for NamespaceIndex {
#[doc(hidden)]
fn new(index: usize) -> Self {
NamespaceIndex(index as _)
}
#[doc(hidden)]
fn index(&self) -> usize {
self.0 as usize
}
}
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct NameIndex(u32);
impl TypedIndex for NameIndex {
#[doc(hidden)]
fn new(index: usize) -> Self {
NameIndex(index as _)
}
#[doc(hidden)]
fn index(&self) -> usize {
self.0 as usize
}
}