Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/cranelift/src/compiled_function.rs
1692 views
1
use crate::{Relocation, mach_reloc_to_reloc, mach_trap_to_trap};
2
use cranelift_codegen::{
3
Final, MachBufferFinalized, MachSrcLoc, ValueLabelsRanges, ir, isa::unwind::CfaUnwindInfo,
4
isa::unwind::UnwindInfo,
5
};
6
use wasmtime_environ::{FilePos, InstructionAddressMap, PrimaryMap, TrapInformation};
7
8
#[derive(Debug, Clone, PartialEq, Eq, Default)]
9
/// Metadata to translate from binary offsets back to the original
10
/// location found in the wasm input.
11
pub struct FunctionAddressMap {
12
/// An array of data for the instructions in this function, indicating where
13
/// each instruction maps back to in the original function.
14
///
15
/// This array is sorted least-to-greatest by the `code_offset` field.
16
/// Additionally the span of each `InstructionAddressMap` is implicitly the
17
/// gap between it and the next item in the array.
18
pub instructions: Box<[InstructionAddressMap]>,
19
20
/// Function's initial offset in the source file, specified in bytes from
21
/// the front of the file.
22
pub start_srcloc: FilePos,
23
24
/// Function's end offset in the source file, specified in bytes from
25
/// the front of the file.
26
pub end_srcloc: FilePos,
27
28
/// Generated function body offset if applicable, otherwise 0.
29
pub body_offset: usize,
30
31
/// Generated function body length.
32
pub body_len: u32,
33
}
34
35
/// The metadata for the compiled function.
36
#[derive(Default)]
37
pub struct CompiledFunctionMetadata {
38
/// The function address map to translate from binary
39
/// back to the original source.
40
pub address_map: FunctionAddressMap,
41
/// The unwind information.
42
pub unwind_info: Option<UnwindInfo>,
43
/// CFA-based unwind information for DWARF debugging support.
44
pub cfa_unwind_info: Option<CfaUnwindInfo>,
45
/// Mapping of value labels and their locations.
46
pub value_labels_ranges: ValueLabelsRanges,
47
/// Allocated stack slots.
48
pub sized_stack_slots: ir::StackSlots,
49
/// Start source location.
50
pub start_srcloc: FilePos,
51
/// End source location.
52
pub end_srcloc: FilePos,
53
}
54
55
/// Compiled function: machine code body, jump table offsets, and unwind information.
56
pub struct CompiledFunction {
57
/// The machine code buffer for this function.
58
pub buffer: MachBufferFinalized<Final>,
59
/// What names each name ref corresponds to.
60
name_map: PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,
61
/// The alignment for the compiled function.
62
pub alignment: u32,
63
/// The metadata for the compiled function, including unwind information
64
/// the function address map.
65
metadata: CompiledFunctionMetadata,
66
}
67
68
impl CompiledFunction {
69
/// Creates a [CompiledFunction] from a [`cranelift_codegen::MachBufferFinalized<Final>`]
70
/// This function uses the information in the machine buffer to derive the traps and relocations
71
/// fields. The compiled function metadata is loaded with the default values.
72
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
/// Returns an iterator to the function's relocation information.
86
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
/// Returns an iterator to the function's trap information.
94
pub fn traps(&self) -> impl Iterator<Item = TrapInformation> + '_ {
95
self.buffer.traps().iter().filter_map(mach_trap_to_trap)
96
}
97
98
/// Get the function's address map from the metadata.
99
pub fn address_map(&self) -> &FunctionAddressMap {
100
&self.metadata.address_map
101
}
102
103
/// Create and return the compiled function address map from the original source offset
104
/// and length.
105
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
/// Get a reference to the unwind information from the
133
/// function's metadata.
134
pub fn unwind_info(&self) -> Option<&UnwindInfo> {
135
self.metadata.unwind_info.as_ref()
136
}
137
138
/// Get a reference to the compiled function metadata.
139
pub fn metadata(&self) -> &CompiledFunctionMetadata {
140
&self.metadata
141
}
142
143
/// Set the value labels ranges in the function's metadata.
144
pub fn set_value_labels_ranges(&mut self, ranges: ValueLabelsRanges) {
145
self.metadata.value_labels_ranges = ranges;
146
}
147
148
/// Set the unwind info in the function's metadata.
149
pub fn set_unwind_info(&mut self, unwind: UnwindInfo) {
150
self.metadata.unwind_info = Some(unwind);
151
}
152
153
/// Set the CFA-based unwind info in the function's metadata.
154
pub fn set_cfa_unwind_info(&mut self, unwind: CfaUnwindInfo) {
155
self.metadata.cfa_unwind_info = Some(unwind);
156
}
157
158
/// Set the sized stack slots.
159
pub fn set_sized_stack_slots(&mut self, slots: ir::StackSlots) {
160
self.metadata.sized_stack_slots = slots;
161
}
162
}
163
164
// Collects an iterator of `InstructionAddressMap` into a `Vec` for insertion
165
// into a `FunctionAddressMap`. This will automatically coalesce adjacent
166
// instructions which map to the same original source position.
167
fn 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 this instruction is adjacent to the previous and has the same
179
// source location then we can "coalesce" it with the current
180
// instruction.
181
if cur_offset + cur_len == offset && loc == cur_loc {
182
cur_len += len;
183
continue;
184
}
185
186
// Push an entry for the previous source item.
187
ret.push(InstructionAddressMap {
188
srcloc: cvt(cur_loc),
189
code_offset: cur_offset,
190
});
191
// And push a "dummy" entry if necessary to cover the span of ranges,
192
// if any, between the previous source offset and this one.
193
if cur_offset + cur_len != offset {
194
ret.push(InstructionAddressMap {
195
srcloc: FilePos::default(),
196
code_offset: cur_offset + cur_len,
197
});
198
}
199
// Update our current location to get extended later or pushed on at
200
// the end.
201
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
}
226
227