wasmtime_internal_cranelift/
compiled_function.rs1use std::ops::Range;
2
3use crate::{Relocation, mach_reloc_to_reloc, mach_trap_to_trap};
4use cranelift_codegen::{
5 Final, MachBufferFinalized, MachBufferFrameLayout, MachSrcLoc, ValueLabelsRanges, ir,
6 isa::unwind::CfaUnwindInfo, isa::unwind::UnwindInfo,
7};
8use wasmtime_environ::{
9 FilePos, FrameStateSlotBuilder, InstructionAddressMap, ModulePC, PrimaryMap, TrapInformation,
10 Tunables,
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, Default)]
14pub struct FunctionAddressMap {
17 pub instructions: Box<[InstructionAddressMap]>,
24
25 pub start_srcloc: FilePos,
28
29 pub end_srcloc: FilePos,
32
33 pub body_offset: usize,
35
36 pub body_len: u32,
38}
39
40#[derive(Default)]
42pub struct CompiledFunctionMetadata {
43 pub address_map: FunctionAddressMap,
46 pub unwind_info: Option<UnwindInfo>,
48 pub cfa_unwind_info: Option<CfaUnwindInfo>,
50 pub value_labels_ranges: ValueLabelsRanges,
52 pub start_srcloc: FilePos,
54 pub end_srcloc: FilePos,
56}
57
58pub struct CompiledFunction {
60 pub buffer: MachBufferFinalized<Final>,
62 name_map: PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,
64 pub alignment: u32,
66 metadata: CompiledFunctionMetadata,
69 pub debug_slot_descriptor: Option<FrameStateSlotBuilder>,
71 pub breakpoint_patch_points: Vec<(ModulePC, Range<u32>)>,
73}
74
75impl CompiledFunction {
76 pub fn new(
80 buffer: MachBufferFinalized<Final>,
81 name_map: PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,
82 alignment: u32,
83 ) -> Self {
84 let mut this = Self {
85 buffer,
86 name_map,
87 alignment,
88 metadata: Default::default(),
89 debug_slot_descriptor: None,
90 breakpoint_patch_points: vec![],
91 };
92 this.finalize_breakpoints();
93
94 this
95 }
96
97 fn finalize_breakpoints(&mut self) {
101 let mut tags = self.buffer.debug_tags().peekable();
105 let mut patchable_callsites = self.buffer.patchable_call_sites().peekable();
106
107 while let (Some(tag), Some(patchable_callsite)) = (tags.peek(), patchable_callsites.peek())
108 {
109 if tag.offset > patchable_callsite.ret_addr {
110 patchable_callsites.next();
111 continue;
112 }
113 if patchable_callsite.ret_addr > tag.offset {
114 tags.next();
115 continue;
116 }
117 assert_eq!(tag.offset, patchable_callsite.ret_addr);
118
119 assert!(tag.tags.len() >= 3);
124 let ir::DebugTag::User(wasm_pc_raw) = tag.tags[tag.tags.len() - 2] else {
125 panic!("invalid tag")
126 };
127
128 let patchable_start = patchable_callsite.ret_addr - patchable_callsite.len;
129 let patchable_end = patchable_callsite.ret_addr;
130
131 self.breakpoint_patch_points
132 .push((ModulePC::new(wasm_pc_raw), patchable_start..patchable_end));
133
134 tags.next();
135 patchable_callsites.next();
136 }
137 }
138
139 pub fn relocations(&self) -> impl Iterator<Item = Relocation> + '_ {
141 self.buffer
142 .relocs()
143 .iter()
144 .map(|r| mach_reloc_to_reloc(r, &self.name_map))
145 }
146
147 pub fn traps<'a>(
149 &'a self,
150 tunables: &'a Tunables,
151 ) -> impl Iterator<Item = TrapInformation> + 'a {
152 self.buffer
153 .traps()
154 .iter()
155 .filter_map(move |t| mach_trap_to_trap(t, tunables))
156 }
157
158 pub fn address_map(&self) -> &FunctionAddressMap {
160 &self.metadata.address_map
161 }
162
163 pub fn set_address_map(&mut self, offset: u32, length: u32, with_instruction_addresses: bool) {
166 assert!((offset + length) <= u32::max_value());
167 let len = self.buffer.data().len();
168 let srclocs = self
169 .buffer
170 .get_srclocs_sorted()
171 .into_iter()
172 .map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start)));
173 let instructions = if with_instruction_addresses {
174 collect_address_maps(len.try_into().unwrap(), srclocs)
175 } else {
176 Default::default()
177 };
178 let start_srcloc = FilePos::new(offset);
179 let end_srcloc = FilePos::new(offset + length);
180
181 let address_map = FunctionAddressMap {
182 instructions: instructions.into(),
183 start_srcloc,
184 end_srcloc,
185 body_offset: 0,
186 body_len: len.try_into().unwrap(),
187 };
188
189 self.metadata.address_map = address_map;
190 }
191
192 pub fn unwind_info(&self) -> Option<&UnwindInfo> {
195 self.metadata.unwind_info.as_ref()
196 }
197
198 pub fn metadata(&self) -> &CompiledFunctionMetadata {
200 &self.metadata
201 }
202
203 pub fn set_value_labels_ranges(&mut self, ranges: ValueLabelsRanges) {
205 self.metadata.value_labels_ranges = ranges;
206 }
207
208 pub fn set_unwind_info(&mut self, unwind: UnwindInfo) {
210 self.metadata.unwind_info = Some(unwind);
211 }
212
213 pub fn set_cfa_unwind_info(&mut self, unwind: CfaUnwindInfo) {
215 self.metadata.cfa_unwind_info = Some(unwind);
216 }
217
218 pub fn frame_layout(&self) -> &MachBufferFrameLayout {
220 self.buffer
221 .frame_layout()
222 .expect("Single-function MachBuffer must have frame layout information")
223 }
224
225 pub fn breakpoint_patches(&self) -> impl Iterator<Item = (ModulePC, Range<u32>)> + '_ {
229 self.breakpoint_patch_points.iter().cloned()
230 }
231}
232
233fn collect_address_maps(
237 code_size: u32,
238 iter: impl IntoIterator<Item = (ir::SourceLoc, u32, u32)>,
239) -> Vec<InstructionAddressMap> {
240 let mut iter = iter.into_iter();
241 let (mut cur_loc, mut cur_offset, mut cur_len) = match iter.next() {
242 Some(i) => i,
243 None => return Vec::new(),
244 };
245 let mut ret = Vec::new();
246 for (loc, offset, len) in iter {
247 if cur_offset + cur_len == offset && loc == cur_loc {
251 cur_len += len;
252 continue;
253 }
254
255 ret.push(InstructionAddressMap {
257 srcloc: cvt(cur_loc),
258 code_offset: cur_offset,
259 });
260 if cur_offset + cur_len != offset {
263 ret.push(InstructionAddressMap {
264 srcloc: FilePos::default(),
265 code_offset: cur_offset + cur_len,
266 });
267 }
268 cur_loc = loc;
271 cur_offset = offset;
272 cur_len = len;
273 }
274 ret.push(InstructionAddressMap {
275 srcloc: cvt(cur_loc),
276 code_offset: cur_offset,
277 });
278 if cur_offset + cur_len != code_size {
279 ret.push(InstructionAddressMap {
280 srcloc: FilePos::default(),
281 code_offset: cur_offset + cur_len,
282 });
283 }
284
285 return ret;
286
287 fn cvt(loc: ir::SourceLoc) -> FilePos {
288 if loc.is_default() {
289 FilePos::default()
290 } else {
291 FilePos::new(loc.bits())
292 }
293 }
294}