Path: blob/main/crates/cranelift/src/compiled_function.rs
1692 views
use crate::{Relocation, mach_reloc_to_reloc, mach_trap_to_trap};1use cranelift_codegen::{2Final, MachBufferFinalized, MachSrcLoc, ValueLabelsRanges, ir, isa::unwind::CfaUnwindInfo,3isa::unwind::UnwindInfo,4};5use wasmtime_environ::{FilePos, InstructionAddressMap, PrimaryMap, TrapInformation};67#[derive(Debug, Clone, PartialEq, Eq, Default)]8/// Metadata to translate from binary offsets back to the original9/// location found in the wasm input.10pub struct FunctionAddressMap {11/// An array of data for the instructions in this function, indicating where12/// each instruction maps back to in the original function.13///14/// This array is sorted least-to-greatest by the `code_offset` field.15/// Additionally the span of each `InstructionAddressMap` is implicitly the16/// gap between it and the next item in the array.17pub instructions: Box<[InstructionAddressMap]>,1819/// Function's initial offset in the source file, specified in bytes from20/// the front of the file.21pub start_srcloc: FilePos,2223/// Function's end offset in the source file, specified in bytes from24/// the front of the file.25pub end_srcloc: FilePos,2627/// Generated function body offset if applicable, otherwise 0.28pub body_offset: usize,2930/// Generated function body length.31pub body_len: u32,32}3334/// The metadata for the compiled function.35#[derive(Default)]36pub struct CompiledFunctionMetadata {37/// The function address map to translate from binary38/// back to the original source.39pub address_map: FunctionAddressMap,40/// The unwind information.41pub unwind_info: Option<UnwindInfo>,42/// CFA-based unwind information for DWARF debugging support.43pub cfa_unwind_info: Option<CfaUnwindInfo>,44/// Mapping of value labels and their locations.45pub value_labels_ranges: ValueLabelsRanges,46/// Allocated stack slots.47pub sized_stack_slots: ir::StackSlots,48/// Start source location.49pub start_srcloc: FilePos,50/// End source location.51pub end_srcloc: FilePos,52}5354/// Compiled function: machine code body, jump table offsets, and unwind information.55pub struct CompiledFunction {56/// The machine code buffer for this function.57pub buffer: MachBufferFinalized<Final>,58/// What names each name ref corresponds to.59name_map: PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,60/// The alignment for the compiled function.61pub alignment: u32,62/// The metadata for the compiled function, including unwind information63/// the function address map.64metadata: CompiledFunctionMetadata,65}6667impl CompiledFunction {68/// Creates a [CompiledFunction] from a [`cranelift_codegen::MachBufferFinalized<Final>`]69/// This function uses the information in the machine buffer to derive the traps and relocations70/// fields. The compiled function metadata is loaded with the default values.71pub fn new(72buffer: MachBufferFinalized<Final>,73name_map: PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,74alignment: u32,75) -> Self {76Self {77buffer,78name_map,79alignment,80metadata: Default::default(),81}82}8384/// Returns an iterator to the function's relocation information.85pub fn relocations(&self) -> impl Iterator<Item = Relocation> + '_ {86self.buffer87.relocs()88.iter()89.map(|r| mach_reloc_to_reloc(r, &self.name_map))90}9192/// Returns an iterator to the function's trap information.93pub fn traps(&self) -> impl Iterator<Item = TrapInformation> + '_ {94self.buffer.traps().iter().filter_map(mach_trap_to_trap)95}9697/// Get the function's address map from the metadata.98pub fn address_map(&self) -> &FunctionAddressMap {99&self.metadata.address_map100}101102/// Create and return the compiled function address map from the original source offset103/// and length.104pub fn set_address_map(&mut self, offset: u32, length: u32, with_instruction_addresses: bool) {105assert!((offset + length) <= u32::max_value());106let len = self.buffer.data().len();107let srclocs = self108.buffer109.get_srclocs_sorted()110.into_iter()111.map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start)));112let instructions = if with_instruction_addresses {113collect_address_maps(len.try_into().unwrap(), srclocs)114} else {115Default::default()116};117let start_srcloc = FilePos::new(offset);118let end_srcloc = FilePos::new(offset + length);119120let address_map = FunctionAddressMap {121instructions: instructions.into(),122start_srcloc,123end_srcloc,124body_offset: 0,125body_len: len.try_into().unwrap(),126};127128self.metadata.address_map = address_map;129}130131/// Get a reference to the unwind information from the132/// function's metadata.133pub fn unwind_info(&self) -> Option<&UnwindInfo> {134self.metadata.unwind_info.as_ref()135}136137/// Get a reference to the compiled function metadata.138pub fn metadata(&self) -> &CompiledFunctionMetadata {139&self.metadata140}141142/// Set the value labels ranges in the function's metadata.143pub fn set_value_labels_ranges(&mut self, ranges: ValueLabelsRanges) {144self.metadata.value_labels_ranges = ranges;145}146147/// Set the unwind info in the function's metadata.148pub fn set_unwind_info(&mut self, unwind: UnwindInfo) {149self.metadata.unwind_info = Some(unwind);150}151152/// Set the CFA-based unwind info in the function's metadata.153pub fn set_cfa_unwind_info(&mut self, unwind: CfaUnwindInfo) {154self.metadata.cfa_unwind_info = Some(unwind);155}156157/// Set the sized stack slots.158pub fn set_sized_stack_slots(&mut self, slots: ir::StackSlots) {159self.metadata.sized_stack_slots = slots;160}161}162163// Collects an iterator of `InstructionAddressMap` into a `Vec` for insertion164// into a `FunctionAddressMap`. This will automatically coalesce adjacent165// instructions which map to the same original source position.166fn collect_address_maps(167code_size: u32,168iter: impl IntoIterator<Item = (ir::SourceLoc, u32, u32)>,169) -> Vec<InstructionAddressMap> {170let mut iter = iter.into_iter();171let (mut cur_loc, mut cur_offset, mut cur_len) = match iter.next() {172Some(i) => i,173None => return Vec::new(),174};175let mut ret = Vec::new();176for (loc, offset, len) in iter {177// If this instruction is adjacent to the previous and has the same178// source location then we can "coalesce" it with the current179// instruction.180if cur_offset + cur_len == offset && loc == cur_loc {181cur_len += len;182continue;183}184185// Push an entry for the previous source item.186ret.push(InstructionAddressMap {187srcloc: cvt(cur_loc),188code_offset: cur_offset,189});190// And push a "dummy" entry if necessary to cover the span of ranges,191// if any, between the previous source offset and this one.192if cur_offset + cur_len != offset {193ret.push(InstructionAddressMap {194srcloc: FilePos::default(),195code_offset: cur_offset + cur_len,196});197}198// Update our current location to get extended later or pushed on at199// the end.200cur_loc = loc;201cur_offset = offset;202cur_len = len;203}204ret.push(InstructionAddressMap {205srcloc: cvt(cur_loc),206code_offset: cur_offset,207});208if cur_offset + cur_len != code_size {209ret.push(InstructionAddressMap {210srcloc: FilePos::default(),211code_offset: cur_offset + cur_len,212});213}214215return ret;216217fn cvt(loc: ir::SourceLoc) -> FilePos {218if loc.is_default() {219FilePos::default()220} else {221FilePos::new(loc.bits())222}223}224}225226227