use crate::{mach_reloc_to_reloc, mach_trap_to_trap, Relocation};
use cranelift_codegen::{
ir, ir::UserExternalNameRef, isa::unwind::CfaUnwindInfo, isa::unwind::UnwindInfo, Final,
MachBufferFinalized, MachSrcLoc, ValueLabelsRanges,
};
use wasmtime_environ::{FilePos, InstructionAddressMap, TrapInformation};
pub trait CompiledFuncEnv {
fn resolve_user_external_name_ref(&self, external: UserExternalNameRef) -> (u32, u32);
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct FunctionAddressMap {
pub instructions: Box<[InstructionAddressMap]>,
pub start_srcloc: FilePos,
pub end_srcloc: FilePos,
pub body_offset: usize,
pub body_len: u32,
}
#[derive(Default)]
pub struct CompiledFunctionMetadata {
pub address_map: FunctionAddressMap,
pub unwind_info: Option<UnwindInfo>,
pub cfa_unwind_info: Option<CfaUnwindInfo>,
pub value_labels_ranges: ValueLabelsRanges,
pub sized_stack_slots: ir::StackSlots,
pub start_srcloc: FilePos,
pub end_srcloc: FilePos,
}
pub struct CompiledFunction<E: CompiledFuncEnv> {
pub buffer: MachBufferFinalized<Final>,
env: E,
pub alignment: u32,
metadata: CompiledFunctionMetadata,
}
impl<E: CompiledFuncEnv> CompiledFunction<E>
where
E: CompiledFuncEnv,
{
pub fn new(buffer: MachBufferFinalized<Final>, env: E, alignment: u32) -> Self {
Self {
buffer,
env,
alignment,
metadata: Default::default(),
}
}
pub fn relocations(&self) -> impl Iterator<Item = Relocation> + '_ {
self.buffer.relocs().iter().map(|r| {
mach_reloc_to_reloc(r, |external| {
self.env.resolve_user_external_name_ref(external)
})
})
}
pub fn traps(&self) -> impl Iterator<Item = TrapInformation> + '_ {
self.buffer.traps().iter().filter_map(mach_trap_to_trap)
}
pub fn address_map(&self) -> &FunctionAddressMap {
&self.metadata.address_map
}
pub fn set_address_map(&mut self, offset: u32, length: u32, with_instruction_addresses: bool) {
assert!((offset + length) <= u32::max_value());
let len = self.buffer.data().len();
let srclocs = self
.buffer
.get_srclocs_sorted()
.into_iter()
.map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start)));
let instructions = if with_instruction_addresses {
collect_address_maps(len as u32, srclocs)
} else {
Default::default()
};
let start_srcloc = FilePos::new(offset);
let end_srcloc = FilePos::new(offset + length);
let address_map = FunctionAddressMap {
instructions: instructions.into(),
start_srcloc,
end_srcloc,
body_offset: 0,
body_len: len as u32,
};
self.metadata.address_map = address_map;
}
pub fn unwind_info(&self) -> Option<&UnwindInfo> {
self.metadata.unwind_info.as_ref()
}
pub fn metadata(&self) -> &CompiledFunctionMetadata {
&self.metadata
}
pub fn set_value_labels_ranges(&mut self, ranges: ValueLabelsRanges) {
self.metadata.value_labels_ranges = ranges;
}
pub fn set_unwind_info(&mut self, unwind: UnwindInfo) {
self.metadata.unwind_info = Some(unwind);
}
pub fn set_cfa_unwind_info(&mut self, unwind: CfaUnwindInfo) {
self.metadata.cfa_unwind_info = Some(unwind);
}
pub fn set_sized_stack_slots(&mut self, slots: ir::StackSlots) {
self.metadata.sized_stack_slots = slots;
}
}
fn collect_address_maps(
code_size: u32,
iter: impl IntoIterator<Item = (ir::SourceLoc, u32, u32)>,
) -> Vec<InstructionAddressMap> {
let mut iter = iter.into_iter();
let (mut cur_loc, mut cur_offset, mut cur_len) = match iter.next() {
Some(i) => i,
None => return Vec::new(),
};
let mut ret = Vec::new();
for (loc, offset, len) in iter {
if cur_offset + cur_len == offset && loc == cur_loc {
cur_len += len;
continue;
}
ret.push(InstructionAddressMap {
srcloc: cvt(cur_loc),
code_offset: cur_offset,
});
if cur_offset + cur_len != offset {
ret.push(InstructionAddressMap {
srcloc: FilePos::default(),
code_offset: cur_offset + cur_len,
});
}
cur_loc = loc;
cur_offset = offset;
cur_len = len;
}
ret.push(InstructionAddressMap {
srcloc: cvt(cur_loc),
code_offset: cur_offset,
});
if cur_offset + cur_len != code_size {
ret.push(InstructionAddressMap {
srcloc: FilePos::default(),
code_offset: cur_offset + cur_len,
});
}
return ret;
fn cvt(loc: ir::SourceLoc) -> FilePos {
if loc.is_default() {
FilePos::default()
} else {
FilePos::new(loc.bits())
}
}
}