wasmtime_internal_cranelift/
compiled_function.rs1use crate::{Relocation, mach_reloc_to_reloc, mach_trap_to_trap};
2use cranelift_codegen::{
3 Final, MachBufferFinalized, MachBufferFrameLayout, MachSrcLoc, ValueLabelsRanges, ir,
4 isa::unwind::CfaUnwindInfo, isa::unwind::UnwindInfo,
5};
6use wasmtime_environ::{
7 FilePos, FrameStateSlotBuilder, InstructionAddressMap, PrimaryMap, TrapInformation,
8};
9
10#[derive(Debug, Clone, PartialEq, Eq, Default)]
11pub struct FunctionAddressMap {
14 pub instructions: Box<[InstructionAddressMap]>,
21
22 pub start_srcloc: FilePos,
25
26 pub end_srcloc: FilePos,
29
30 pub body_offset: usize,
32
33 pub body_len: u32,
35}
36
37#[derive(Default)]
39pub struct CompiledFunctionMetadata {
40 pub address_map: FunctionAddressMap,
43 pub unwind_info: Option<UnwindInfo>,
45 pub cfa_unwind_info: Option<CfaUnwindInfo>,
47 pub value_labels_ranges: ValueLabelsRanges,
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 pub debug_slot_descriptor: Option<FrameStateSlotBuilder>,
68}
69
70impl CompiledFunction {
71 pub fn new(
75 buffer: MachBufferFinalized<Final>,
76 name_map: PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,
77 alignment: u32,
78 ) -> Self {
79 Self {
80 buffer,
81 name_map,
82 alignment,
83 metadata: Default::default(),
84 debug_slot_descriptor: None,
85 }
86 }
87
88 pub fn relocations(&self) -> impl Iterator<Item = Relocation> + '_ {
90 self.buffer
91 .relocs()
92 .iter()
93 .map(|r| mach_reloc_to_reloc(r, &self.name_map))
94 }
95
96 pub fn traps(&self) -> impl Iterator<Item = TrapInformation> + '_ {
98 self.buffer.traps().iter().filter_map(mach_trap_to_trap)
99 }
100
101 pub fn address_map(&self) -> &FunctionAddressMap {
103 &self.metadata.address_map
104 }
105
106 pub fn set_address_map(&mut self, offset: u32, length: u32, with_instruction_addresses: bool) {
109 assert!((offset + length) <= u32::max_value());
110 let len = self.buffer.data().len();
111 let srclocs = self
112 .buffer
113 .get_srclocs_sorted()
114 .into_iter()
115 .map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start)));
116 let instructions = if with_instruction_addresses {
117 collect_address_maps(len.try_into().unwrap(), srclocs)
118 } else {
119 Default::default()
120 };
121 let start_srcloc = FilePos::new(offset);
122 let end_srcloc = FilePos::new(offset + length);
123
124 let address_map = FunctionAddressMap {
125 instructions: instructions.into(),
126 start_srcloc,
127 end_srcloc,
128 body_offset: 0,
129 body_len: len.try_into().unwrap(),
130 };
131
132 self.metadata.address_map = address_map;
133 }
134
135 pub fn unwind_info(&self) -> Option<&UnwindInfo> {
138 self.metadata.unwind_info.as_ref()
139 }
140
141 pub fn metadata(&self) -> &CompiledFunctionMetadata {
143 &self.metadata
144 }
145
146 pub fn set_value_labels_ranges(&mut self, ranges: ValueLabelsRanges) {
148 self.metadata.value_labels_ranges = ranges;
149 }
150
151 pub fn set_unwind_info(&mut self, unwind: UnwindInfo) {
153 self.metadata.unwind_info = Some(unwind);
154 }
155
156 pub fn set_cfa_unwind_info(&mut self, unwind: CfaUnwindInfo) {
158 self.metadata.cfa_unwind_info = Some(unwind);
159 }
160
161 pub fn frame_layout(&self) -> &MachBufferFrameLayout {
163 self.buffer
164 .frame_layout()
165 .expect("Single-function MachBuffer must have frame layout information")
166 }
167}
168
169fn collect_address_maps(
173 code_size: u32,
174 iter: impl IntoIterator<Item = (ir::SourceLoc, u32, u32)>,
175) -> Vec<InstructionAddressMap> {
176 let mut iter = iter.into_iter();
177 let (mut cur_loc, mut cur_offset, mut cur_len) = match iter.next() {
178 Some(i) => i,
179 None => return Vec::new(),
180 };
181 let mut ret = Vec::new();
182 for (loc, offset, len) in iter {
183 if cur_offset + cur_len == offset && loc == cur_loc {
187 cur_len += len;
188 continue;
189 }
190
191 ret.push(InstructionAddressMap {
193 srcloc: cvt(cur_loc),
194 code_offset: cur_offset,
195 });
196 if cur_offset + cur_len != offset {
199 ret.push(InstructionAddressMap {
200 srcloc: FilePos::default(),
201 code_offset: cur_offset + cur_len,
202 });
203 }
204 cur_loc = loc;
207 cur_offset = offset;
208 cur_len = len;
209 }
210 ret.push(InstructionAddressMap {
211 srcloc: cvt(cur_loc),
212 code_offset: cur_offset,
213 });
214 if cur_offset + cur_len != code_size {
215 ret.push(InstructionAddressMap {
216 srcloc: FilePos::default(),
217 code_offset: cur_offset + cur_len,
218 });
219 }
220
221 return ret;
222
223 fn cvt(loc: ir::SourceLoc) -> FilePos {
224 if loc.is_default() {
225 FilePos::default()
226 } else {
227 FilePos::new(loc.bits())
228 }
229 }
230}