1#![expect(
7 clippy::cast_possible_truncation,
8 clippy::cast_sign_loss,
9 reason = "haven't had a chance to fix these yet"
10)]
11
12use crate::CompiledFunctionMetadata;
13use core::fmt;
14use cranelift_codegen::isa::TargetIsa;
15use object::write::SymbolId;
16use std::collections::HashMap;
17use wasmtime_environ::{
18 DefinedFuncIndex, DefinedMemoryIndex, EntityRef, MemoryIndex, ModuleTranslation,
19 OwnedMemoryIndex, PrimaryMap, PtrSize, StaticModuleIndex, Tunables, VMOffsets,
20};
21
22#[derive(Debug, Clone)]
24pub enum ModuleMemoryOffset {
25 None,
27 Defined(u32),
29 Imported {
31 offset_to_vm_memory_definition: u32,
34 offset_to_memory_base: u32,
37 },
38}
39
40type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>;
41
42pub struct Compilation<'a> {
49 translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
54
55 get_func:
60 &'a dyn Fn(StaticModuleIndex, DefinedFuncIndex) -> (SymbolId, &'a CompiledFunctionMetadata),
61
62 dwarf_package_bytes: Option<&'a [u8]>,
65
66 tunables: &'a Tunables,
68
69 symbol_index_to_id: Vec<SymbolId>,
72 symbol_id_to_index: HashMap<SymbolId, (usize, StaticModuleIndex, DefinedFuncIndex)>,
73
74 module_memory_offsets: PrimaryMap<StaticModuleIndex, ModuleMemoryOffset>,
78}
79
80impl<'a> Compilation<'a> {
81 pub fn new(
82 isa: &dyn TargetIsa,
83 translations: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
84 get_func: &'a dyn Fn(
85 StaticModuleIndex,
86 DefinedFuncIndex,
87 ) -> (SymbolId, &'a CompiledFunctionMetadata),
88 dwarf_package_bytes: Option<&'a [u8]>,
89 tunables: &'a Tunables,
90 ) -> Compilation<'a> {
91 let mut module_memory_offsets = PrimaryMap::new();
94 for (i, translation) in translations {
95 let ofs = VMOffsets::new(
96 isa.triple().architecture.pointer_width().unwrap().bytes(),
97 &translation.module,
98 );
99
100 let memory_offset = if ofs.num_imported_memories > 0 {
101 let index = MemoryIndex::new(0);
102 ModuleMemoryOffset::Imported {
103 offset_to_vm_memory_definition: ofs.vmctx_vmmemory_import(index)
104 + u32::from(ofs.vmmemory_import_from()),
105 offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(),
106 }
107 } else if ofs.num_owned_memories > 0 {
108 let index = OwnedMemoryIndex::new(0);
109 ModuleMemoryOffset::Defined(ofs.vmctx_vmmemory_definition_base(index))
110 } else if ofs.num_defined_memories > 0 {
111 let index = DefinedMemoryIndex::new(0);
112 ModuleMemoryOffset::Imported {
113 offset_to_vm_memory_definition: ofs.vmctx_vmmemory_pointer(index),
114 offset_to_memory_base: ofs.ptr.vmmemory_definition_base().into(),
115 }
116 } else {
117 ModuleMemoryOffset::None
118 };
119 let j = module_memory_offsets.push(memory_offset);
120 assert_eq!(i, j);
121 }
122
123 let mut symbol_index_to_id = Vec::new();
125 let mut symbol_id_to_index = HashMap::new();
126
127 for (module, translation) in translations {
128 for func in translation.module.defined_func_indices() {
129 let (sym, _func) = get_func(module, func);
130 symbol_id_to_index.insert(sym, (symbol_index_to_id.len(), module, func));
131 symbol_index_to_id.push(sym);
132 }
133 }
134
135 Compilation {
136 translations,
137 get_func,
138 dwarf_package_bytes,
139 tunables,
140 symbol_index_to_id,
141 symbol_id_to_index,
142 module_memory_offsets,
143 }
144 }
145
146 fn indexes(&self) -> impl Iterator<Item = (StaticModuleIndex, DefinedFuncIndex)> + use<'_> {
151 self.translations
152 .iter()
153 .flat_map(|(i, t)| t.module.defined_func_indices().map(move |j| (i, j)))
154 }
155
156 fn functions(
159 &self,
160 ) -> impl Iterator<Item = (StaticModuleIndex, usize, &'a CompiledFunctionMetadata)> + '_ {
161 self.indexes().map(move |(module, func)| {
162 let (sym, func) = self.function(module, func);
163 (module, sym, func)
164 })
165 }
166
167 fn function(
169 &self,
170 module: StaticModuleIndex,
171 func: DefinedFuncIndex,
172 ) -> (usize, &'a CompiledFunctionMetadata) {
173 let (sym, func) = (self.get_func)(module, func);
174 (self.symbol_id_to_index[&sym].0, func)
175 }
176
177 pub fn symbol_id(&self, sym: usize) -> SymbolId {
180 self.symbol_index_to_id[sym]
181 }
182}
183
184impl<'a> fmt::Debug for Compilation<'a> {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 write!(f, "[")?;
188 let mut is_first_module = true;
189 for (i, translation) in self.translations {
190 if !is_first_module {
191 write!(f, ", ")?;
192 } else {
193 is_first_module = false;
194 }
195 write!(f, "#{}", i.as_u32())?;
196 if let Some(name) = translation.debuginfo.name_section.module_name {
197 write!(f, ": {name}")?;
198 }
199 }
200 write!(f, "]")
201 }
202}
203
204pub use write_debuginfo::{emit_dwarf, DwarfSectionRelocTarget};
205
206mod gc;
207mod transform;
208mod write_debuginfo;