#![expect(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
reason = "haven't had a chance to fix these yet"
)]
use crate::CompiledFunctionMetadata;
use core::fmt;
use cranelift_codegen::isa::TargetIsa;
use object::write::SymbolId;
use std::collections::HashMap;
use wasmtime_environ::{
DefinedFuncIndex, DefinedMemoryIndex, EntityRef, MemoryIndex, ModuleTranslation,
OwnedMemoryIndex, PrimaryMap, PtrSize, StaticModuleIndex, Tunables, VMOffsets,
};
#[derive(Debug, Clone)]
pub enum ModuleMemoryOffset {
None,
Defined(u32),
Imported {
offset_to_vm_memory_definition: u32,
offset_to_memory_base: u32,
},
}
type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>;
pub struct Compilation<'a> {
translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
get_func:
&'a dyn Fn(StaticModuleIndex, DefinedFuncIndex) -> (SymbolId, &'a CompiledFunctionMetadata),
dwarf_package_bytes: Option<&'a [u8]>,
tunables: &'a Tunables,
symbol_index_to_id: Vec<SymbolId>,
symbol_id_to_index: HashMap<SymbolId, (usize, StaticModuleIndex, DefinedFuncIndex)>,
module_memory_offsets: PrimaryMap<StaticModuleIndex, ModuleMemoryOffset>,
}
impl<'a> Compilation<'a> {
pub fn new(
isa: &dyn TargetIsa,
translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
get_func: &'a dyn Fn(
StaticModuleIndex,
DefinedFuncIndex,
) -> (SymbolId, &'a CompiledFunctionMetadata),
dwarf_package_bytes: Option<&'a [u8]>,
tunables: &'a Tunables,
) -> Compilation<'a> {
let mut module_memory_offsets = PrimaryMap::new();
for (i, translation) in translations {
let ofs = VMOffsets::new(
isa.triple().architecture.pointer_width().unwrap().bytes(),
&translation.module,
);
let memory_offset = if ofs.num_imported_memories > 0 {
let index = MemoryIndex::new(0);
ModuleMemoryOffset::Imported {
offset_to_vm_memory_definition: ofs.vmctx_vmmemory_import(index)
+ u32::from(ofs.vmmemory_import_from()),
offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(),
}
} else if ofs.num_owned_memories > 0 {
let index = OwnedMemoryIndex::new(0);
ModuleMemoryOffset::Defined(ofs.vmctx_vmmemory_definition_base(index))
} else if ofs.num_defined_memories > 0 {
let index = DefinedMemoryIndex::new(0);
ModuleMemoryOffset::Imported {
offset_to_vm_memory_definition: ofs.vmctx_vmmemory_pointer(index),
offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(),
}
} else {
ModuleMemoryOffset::None
};
let j = module_memory_offsets.push(memory_offset);
assert_eq!(i, j);
}
let mut symbol_index_to_id = Vec::new();
let mut symbol_id_to_index = HashMap::new();
for (module, translation) in translations {
for func in translation.module.defined_func_indices() {
let (sym, _func) = get_func(module, func);
symbol_id_to_index.insert(sym, (symbol_index_to_id.len(), module, func));
symbol_index_to_id.push(sym);
}
}
Compilation {
translations,
get_func,
dwarf_package_bytes,
tunables,
symbol_index_to_id,
symbol_id_to_index,
module_memory_offsets,
}
}
fn indexes(&self) -> impl Iterator<Item = (StaticModuleIndex, DefinedFuncIndex)> + use<'_> {
self.translations
.iter()
.flat_map(|(i, t)| t.module.defined_func_indices().map(move |j| (i, j)))
}
fn functions(
&self,
) -> impl Iterator<Item = (StaticModuleIndex, usize, &'a CompiledFunctionMetadata)> + '_ {
self.indexes().map(move |(module, func)| {
let (sym, func) = self.function(module, func);
(module, sym, func)
})
}
fn function(
&self,
module: StaticModuleIndex,
func: DefinedFuncIndex,
) -> (usize, &'a CompiledFunctionMetadata) {
let (sym, func) = (self.get_func)(module, func);
(self.symbol_id_to_index[&sym].0, func)
}
pub fn symbol_id(&self, sym: usize) -> SymbolId {
self.symbol_index_to_id[sym]
}
}
impl<'a> fmt::Debug for Compilation<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
let mut is_first_module = true;
for (i, translation) in self.translations {
if !is_first_module {
write!(f, ", ")?;
} else {
is_first_module = false;
}
write!(f, "#{}", i.as_u32())?;
if let Some(name) = translation.debuginfo.name_section.module_name {
write!(f, ": {name}")?;
}
}
write!(f, "]")
}
}
pub use write_debuginfo::{DwarfSectionRelocTarget, emit_dwarf};
mod gc;
mod transform;
mod write_debuginfo;