wasmtime_cranelift_shared/
compiled_function.rs1use crate::{mach_reloc_to_reloc, mach_trap_to_trap, Relocation};
2use cranelift_codegen::{
3 ir, ir::UserExternalNameRef, isa::unwind::CfaUnwindInfo, isa::unwind::UnwindInfo, Final,
4 MachBufferFinalized, MachSrcLoc, ValueLabelsRanges,
5};
6use wasmtime_environ::{FilePos, InstructionAddressMap, TrapInformation};
7
8pub trait CompiledFuncEnv {
11 fn resolve_user_external_name_ref(&self, external: UserExternalNameRef) -> (u32, u32);
12}
13
14#[derive(Debug, Clone, PartialEq, Eq, Default)]
15pub struct FunctionAddressMap {
18 pub instructions: Box<[InstructionAddressMap]>,
25
26 pub start_srcloc: FilePos,
29
30 pub end_srcloc: FilePos,
33
34 pub body_offset: usize,
36
37 pub body_len: u32,
39}
40
41#[derive(Default)]
43pub struct CompiledFunctionMetadata {
44 pub address_map: FunctionAddressMap,
47 pub unwind_info: Option<UnwindInfo>,
49 pub cfa_unwind_info: Option<CfaUnwindInfo>,
51 pub value_labels_ranges: ValueLabelsRanges,
53 pub sized_stack_slots: ir::StackSlots,
55 pub start_srcloc: FilePos,
57 pub end_srcloc: FilePos,
59}
60
61pub struct CompiledFunction<E: CompiledFuncEnv> {
63 pub buffer: MachBufferFinalized<Final>,
65 env: E,
67 pub alignment: u32,
69 metadata: CompiledFunctionMetadata,
72}
73
74impl<E: CompiledFuncEnv> CompiledFunction<E>
75where
76 E: CompiledFuncEnv,
77{
78 pub fn new(buffer: MachBufferFinalized<Final>, env: E, alignment: u32) -> Self {
82 Self {
83 buffer,
84 env,
85 alignment,
86 metadata: Default::default(),
87 }
88 }
89
90 pub fn relocations(&self) -> impl Iterator<Item = Relocation> + '_ {
92 self.buffer.relocs().iter().map(|r| {
93 mach_reloc_to_reloc(r, |external| {
94 self.env.resolve_user_external_name_ref(external)
95 })
96 })
97 }
98
99 pub fn traps(&self) -> impl Iterator<Item = TrapInformation> + '_ {
101 self.buffer.traps().iter().filter_map(mach_trap_to_trap)
102 }
103
104 pub fn address_map(&self) -> &FunctionAddressMap {
106 &self.metadata.address_map
107 }
108
109 pub fn set_address_map(&mut self, offset: u32, length: u32, with_instruction_addresses: bool) {
112 assert!((offset + length) <= u32::max_value());
113 let len = self.buffer.data().len();
114 let srclocs = self
115 .buffer
116 .get_srclocs_sorted()
117 .into_iter()
118 .map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start)));
119 let instructions = if with_instruction_addresses {
120 collect_address_maps(len as u32, srclocs)
121 } else {
122 Default::default()
123 };
124 let start_srcloc = FilePos::new(offset);
125 let end_srcloc = FilePos::new(offset + length);
126
127 let address_map = FunctionAddressMap {
128 instructions: instructions.into(),
129 start_srcloc,
130 end_srcloc,
131 body_offset: 0,
132 body_len: len as u32,
133 };
134
135 self.metadata.address_map = address_map;
136 }
137
138 pub fn unwind_info(&self) -> Option<&UnwindInfo> {
141 self.metadata.unwind_info.as_ref()
142 }
143
144 pub fn metadata(&self) -> &CompiledFunctionMetadata {
146 &self.metadata
147 }
148
149 pub fn set_value_labels_ranges(&mut self, ranges: ValueLabelsRanges) {
151 self.metadata.value_labels_ranges = ranges;
152 }
153
154 pub fn set_unwind_info(&mut self, unwind: UnwindInfo) {
156 self.metadata.unwind_info = Some(unwind);
157 }
158
159 pub fn set_cfa_unwind_info(&mut self, unwind: CfaUnwindInfo) {
161 self.metadata.cfa_unwind_info = Some(unwind);
162 }
163
164 pub fn set_sized_stack_slots(&mut self, slots: ir::StackSlots) {
166 self.metadata.sized_stack_slots = slots;
167 }
168}
169
170fn collect_address_maps(
174 code_size: u32,
175 iter: impl IntoIterator<Item = (ir::SourceLoc, u32, u32)>,
176) -> Vec<InstructionAddressMap> {
177 let mut iter = iter.into_iter();
178 let (mut cur_loc, mut cur_offset, mut cur_len) = match iter.next() {
179 Some(i) => i,
180 None => return Vec::new(),
181 };
182 let mut ret = Vec::new();
183 for (loc, offset, len) in iter {
184 if cur_offset + cur_len == offset && loc == cur_loc {
188 cur_len += len;
189 continue;
190 }
191
192 ret.push(InstructionAddressMap {
194 srcloc: cvt(cur_loc),
195 code_offset: cur_offset,
196 });
197 if cur_offset + cur_len != offset {
200 ret.push(InstructionAddressMap {
201 srcloc: FilePos::default(),
202 code_offset: cur_offset + cur_len,
203 });
204 }
205 cur_loc = loc;
208 cur_offset = offset;
209 cur_len = len;
210 }
211 ret.push(InstructionAddressMap {
212 srcloc: cvt(cur_loc),
213 code_offset: cur_offset,
214 });
215 if cur_offset + cur_len != code_size {
216 ret.push(InstructionAddressMap {
217 srcloc: FilePos::default(),
218 code_offset: cur_offset + cur_len,
219 });
220 }
221
222 return ret;
223
224 fn cvt(loc: ir::SourceLoc) -> FilePos {
225 if loc.is_default() {
226 FilePos::default()
227 } else {
228 FilePos::new(loc.bits())
229 }
230 }
231}