wasmtime_cranelift/
compiled_function.rs1use crate::{mach_reloc_to_reloc, mach_trap_to_trap, Relocation};
2use cranelift_codegen::{
3 ir, isa::unwind::CfaUnwindInfo, isa::unwind::UnwindInfo, Final, MachBufferFinalized,
4 MachSrcLoc, ValueLabelsRanges,
5};
6use wasmtime_environ::{FilePos, InstructionAddressMap, PrimaryMap, TrapInformation};
7
8#[derive(Debug, Clone, PartialEq, Eq, Default)]
9pub struct FunctionAddressMap {
12 pub instructions: Box<[InstructionAddressMap]>,
19
20 pub start_srcloc: FilePos,
23
24 pub end_srcloc: FilePos,
27
28 pub body_offset: usize,
30
31 pub body_len: u32,
33}
34
35#[derive(Default)]
37pub struct CompiledFunctionMetadata {
38 pub address_map: FunctionAddressMap,
41 pub unwind_info: Option<UnwindInfo>,
43 pub cfa_unwind_info: Option<CfaUnwindInfo>,
45 pub value_labels_ranges: ValueLabelsRanges,
47 pub sized_stack_slots: ir::StackSlots,
49 pub start_srcloc: FilePos,
51 pub end_srcloc: FilePos,
53}
54
55pub struct CompiledFunction {
57 pub buffer: MachBufferFinalized<Final>,
59 name_map: PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,
61 pub alignment: u32,
63 metadata: CompiledFunctionMetadata,
66}
67
68impl CompiledFunction {
69 pub fn new(
73 buffer: MachBufferFinalized<Final>,
74 name_map: PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,
75 alignment: u32,
76 ) -> Self {
77 Self {
78 buffer,
79 name_map,
80 alignment,
81 metadata: Default::default(),
82 }
83 }
84
85 pub fn relocations(&self) -> impl Iterator<Item = Relocation> + '_ {
87 self.buffer
88 .relocs()
89 .iter()
90 .map(|r| mach_reloc_to_reloc(r, &self.name_map))
91 }
92
93 pub fn traps(&self) -> impl Iterator<Item = TrapInformation> + '_ {
95 self.buffer.traps().iter().filter_map(mach_trap_to_trap)
96 }
97
98 pub fn address_map(&self) -> &FunctionAddressMap {
100 &self.metadata.address_map
101 }
102
103 pub fn set_address_map(&mut self, offset: u32, length: u32, with_instruction_addresses: bool) {
106 assert!((offset + length) <= u32::max_value());
107 let len = self.buffer.data().len();
108 let srclocs = self
109 .buffer
110 .get_srclocs_sorted()
111 .into_iter()
112 .map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start)));
113 let instructions = if with_instruction_addresses {
114 collect_address_maps(len.try_into().unwrap(), srclocs)
115 } else {
116 Default::default()
117 };
118 let start_srcloc = FilePos::new(offset);
119 let end_srcloc = FilePos::new(offset + length);
120
121 let address_map = FunctionAddressMap {
122 instructions: instructions.into(),
123 start_srcloc,
124 end_srcloc,
125 body_offset: 0,
126 body_len: len.try_into().unwrap(),
127 };
128
129 self.metadata.address_map = address_map;
130 }
131
132 pub fn unwind_info(&self) -> Option<&UnwindInfo> {
135 self.metadata.unwind_info.as_ref()
136 }
137
138 pub fn metadata(&self) -> &CompiledFunctionMetadata {
140 &self.metadata
141 }
142
143 pub fn set_value_labels_ranges(&mut self, ranges: ValueLabelsRanges) {
145 self.metadata.value_labels_ranges = ranges;
146 }
147
148 pub fn set_unwind_info(&mut self, unwind: UnwindInfo) {
150 self.metadata.unwind_info = Some(unwind);
151 }
152
153 pub fn set_cfa_unwind_info(&mut self, unwind: CfaUnwindInfo) {
155 self.metadata.cfa_unwind_info = Some(unwind);
156 }
157
158 pub fn set_sized_stack_slots(&mut self, slots: ir::StackSlots) {
160 self.metadata.sized_stack_slots = slots;
161 }
162}
163
164fn collect_address_maps(
168 code_size: u32,
169 iter: impl IntoIterator<Item = (ir::SourceLoc, u32, u32)>,
170) -> Vec<InstructionAddressMap> {
171 let mut iter = iter.into_iter();
172 let (mut cur_loc, mut cur_offset, mut cur_len) = match iter.next() {
173 Some(i) => i,
174 None => return Vec::new(),
175 };
176 let mut ret = Vec::new();
177 for (loc, offset, len) in iter {
178 if cur_offset + cur_len == offset && loc == cur_loc {
182 cur_len += len;
183 continue;
184 }
185
186 ret.push(InstructionAddressMap {
188 srcloc: cvt(cur_loc),
189 code_offset: cur_offset,
190 });
191 if cur_offset + cur_len != offset {
194 ret.push(InstructionAddressMap {
195 srcloc: FilePos::default(),
196 code_offset: cur_offset + cur_len,
197 });
198 }
199 cur_loc = loc;
202 cur_offset = offset;
203 cur_len = len;
204 }
205 ret.push(InstructionAddressMap {
206 srcloc: cvt(cur_loc),
207 code_offset: cur_offset,
208 });
209 if cur_offset + cur_len != code_size {
210 ret.push(InstructionAddressMap {
211 srcloc: FilePos::default(),
212 code_offset: cur_offset + cur_len,
213 });
214 }
215
216 return ret;
217
218 fn cvt(loc: ir::SourceLoc) -> FilePos {
219 if loc.is_default() {
220 FilePos::default()
221 } else {
222 FilePos::new(loc.bits())
223 }
224 }
225}