Write .debug_frame information (#53)

* Write .debug_frame information

* mv map_reg
This commit is contained in:
Yury Delendik
2020-03-11 10:22:51 -05:00
committed by GitHub
parent 2ead747f48
commit f76b36f737
16 changed files with 403 additions and 112 deletions

View File

@@ -6,8 +6,12 @@ use std::boxed::Box;
use crate::HashMap; use crate::HashMap;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
/// Change in the frame layout information. /// Change in the frame layout information.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum FrameLayoutChange { pub enum FrameLayoutChange {
/// Base CallFrameAddress (CFA) pointer moved to different register/offset. /// Base CallFrameAddress (CFA) pointer moved to different register/offset.
CallFrameAddressAt { CallFrameAddressAt {

View File

@@ -4,8 +4,12 @@ use core::fmt;
use core::str; use core::str;
use target_lexicon::{CallingConvention, Triple}; use target_lexicon::{CallingConvention, Triple};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
/// Calling convention identifiers. /// Calling convention identifiers.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum CallConv { pub enum CallConv {
/// Best performance, not ABI-stable /// Best performance, not ABI-stable
Fast, Fast,

140
crates/debug/src/frame.rs Normal file
View File

@@ -0,0 +1,140 @@
use crate::transform::map_reg;
use std::collections::HashMap;
use wasmtime_environ::entity::EntityRef;
use wasmtime_environ::isa::{CallConv, TargetIsa};
use wasmtime_environ::wasm::DefinedFuncIndex;
use wasmtime_environ::{FrameLayoutChange, FrameLayouts};
use gimli::write::{
Address, CallFrameInstruction, CommonInformationEntry as CIEEntry, Error,
FrameDescriptionEntry as FDEEntry, FrameTable,
};
use gimli::{Encoding, Format, Register, X86_64};
fn to_cfi(
isa: &dyn TargetIsa,
change: &FrameLayoutChange,
cfa_def_reg: &mut Register,
cfa_def_offset: &mut i32,
) -> Option<CallFrameInstruction> {
Some(match change {
FrameLayoutChange::CallFrameAddressAt { reg, offset } => {
let mapped = match map_reg(isa, *reg) {
Ok(r) => r,
Err(_) => return None,
};
let offset = (*offset) as i32;
if mapped != *cfa_def_reg && offset != *cfa_def_offset {
*cfa_def_reg = mapped;
*cfa_def_offset = offset;
CallFrameInstruction::Cfa(mapped, offset)
} else if offset != *cfa_def_offset {
*cfa_def_offset = offset;
CallFrameInstruction::CfaOffset(offset)
} else if mapped != *cfa_def_reg {
*cfa_def_reg = mapped;
CallFrameInstruction::CfaRegister(mapped)
} else {
return None;
}
}
FrameLayoutChange::RegAt { reg, cfa_offset } => {
assert!(cfa_offset % -8 == 0);
let cfa_offset = *cfa_offset as i32;
let mapped = match map_reg(isa, *reg) {
Ok(r) => r,
Err(_) => return None,
};
CallFrameInstruction::Offset(mapped, cfa_offset)
}
FrameLayoutChange::ReturnAddressAt { cfa_offset } => {
assert!(cfa_offset % -8 == 0);
let cfa_offset = *cfa_offset as i32;
CallFrameInstruction::Offset(X86_64::RA, cfa_offset)
}
FrameLayoutChange::Preserve => CallFrameInstruction::RememberState,
FrameLayoutChange::Restore => CallFrameInstruction::RestoreState,
})
}
pub fn get_debug_frame_bytes(
funcs: &[(*const u8, usize)],
isa: &dyn TargetIsa,
layouts: &FrameLayouts,
) -> Result<Option<FrameTable>, Error> {
// FIXME Only x86-64 at this moment.
if isa.name() != "x86" || isa.pointer_bits() != 64 {
return Ok(None);
}
let address_size = isa.pointer_bytes();
let encoding = Encoding {
format: Format::Dwarf64,
version: 4,
address_size,
};
let mut frames = FrameTable::default();
let mut cached_cies = HashMap::new();
for (i, f) in funcs.into_iter().enumerate() {
let layout = &layouts[DefinedFuncIndex::new(i)];
// FIXME Can only process functions with SystemV-like prologue.
if layout.call_conv != CallConv::Fast
&& layout.call_conv != CallConv::Cold
&& layout.call_conv != CallConv::SystemV
{
continue;
}
// Caching CIE with similar initial_commands.
let (cie_id, mut cfa_def_reg, mut cfa_def_offset) = {
use std::collections::hash_map::Entry;
match cached_cies.entry(&layout.initial_commands) {
Entry::Occupied(o) => *o.get(),
Entry::Vacant(v) => {
// cfa_def_reg and cfa_def_offset initialized with some random values.
let mut cfa_def_reg = X86_64::RA;
let mut cfa_def_offset = 0i32;
// TODO adjust code_alignment_factor and data_alignment_factor based on ISA.
let mut cie = CIEEntry::new(
encoding,
/* code_alignment_factor = */ 1,
/* data_alignment_factor = */ -8,
/* return_address_register = */ X86_64::RA,
);
for cmd in layout.initial_commands.iter() {
if let Some(instr) = to_cfi(isa, cmd, &mut cfa_def_reg, &mut cfa_def_offset)
{
cie.add_instruction(instr);
}
}
let cie_id = frames.add_cie(cie);
*v.insert((cie_id, cfa_def_reg, cfa_def_offset))
}
}
};
let f_len = f.1 as u32;
let mut fde = FDEEntry::new(
Address::Symbol {
symbol: i,
addend: 0,
},
f_len,
);
for (offset, cmd) in layout.commands.into_iter() {
if let Some(instr) = to_cfi(isa, cmd, &mut cfa_def_reg, &mut cfa_def_offset) {
fde.add_instruction(*offset as u32, instr);
}
}
frames.add_fde(cie_id, fde);
}
Ok(Some(frames))
}

View File

@@ -2,17 +2,19 @@
#![allow(clippy::cast_ptr_alignment)] #![allow(clippy::cast_ptr_alignment)]
use crate::frame::get_debug_frame_bytes;
use anyhow::Error; use anyhow::Error;
use faerie::{Artifact, Decl}; use faerie::{Artifact, Decl};
use more_asserts::assert_gt; use more_asserts::assert_gt;
use target_lexicon::BinaryFormat; use target_lexicon::BinaryFormat;
use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::isa::TargetIsa;
use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges}; use wasmtime_environ::{FrameLayouts, ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges};
pub use crate::read_debuginfo::{read_debuginfo, DebugInfoData, WasmFileInfo}; pub use crate::read_debuginfo::{read_debuginfo, DebugInfoData, WasmFileInfo};
pub use crate::transform::transform_dwarf; pub use crate::transform::transform_dwarf;
pub use crate::write_debuginfo::{emit_dwarf, ResolvedSymbol, SymbolResolver}; pub use crate::write_debuginfo::{emit_dwarf, ResolvedSymbol, SymbolResolver};
mod frame;
mod gc; mod gc;
mod read_debuginfo; mod read_debuginfo;
mod transform; mod transform;
@@ -33,10 +35,21 @@ pub fn emit_debugsections(
debuginfo_data: &DebugInfoData, debuginfo_data: &DebugInfoData,
at: &ModuleAddressMap, at: &ModuleAddressMap,
ranges: &ValueLabelsRanges, ranges: &ValueLabelsRanges,
frame_layouts: &FrameLayouts,
) -> Result<(), Error> { ) -> Result<(), Error> {
let resolver = FunctionRelocResolver {}; let resolver = FunctionRelocResolver {};
let dwarf = transform_dwarf(isa, debuginfo_data, at, vmctx_info, ranges)?; let dwarf = transform_dwarf(isa, debuginfo_data, at, vmctx_info, ranges)?;
emit_dwarf(obj, dwarf, &resolver)?;
let max = at.values().map(|v| v.body_len).fold(0, usize::max);
let mut funcs_bodies = Vec::with_capacity(max as usize);
funcs_bodies.resize(max as usize, 0);
let funcs = at
.values()
.map(|v| (::std::ptr::null(), v.body_len))
.collect::<Vec<(*const u8, usize)>>();
let frames = get_debug_frame_bytes(&funcs, isa, frame_layouts)?;
emit_dwarf(obj, dwarf, &resolver, frames)?;
Ok(()) Ok(())
} }
@@ -57,6 +70,7 @@ pub fn emit_debugsections_image(
vmctx_info: &ModuleVmctxInfo, vmctx_info: &ModuleVmctxInfo,
at: &ModuleAddressMap, at: &ModuleAddressMap,
ranges: &ValueLabelsRanges, ranges: &ValueLabelsRanges,
frame_layouts: &FrameLayouts,
funcs: &[(*const u8, usize)], funcs: &[(*const u8, usize)],
) -> Result<Vec<u8>, Error> { ) -> Result<Vec<u8>, Error> {
let func_offsets = &funcs let func_offsets = &funcs
@@ -79,7 +93,8 @@ pub fn emit_debugsections_image(
let body = unsafe { std::slice::from_raw_parts(segment_body.0, segment_body.1) }; let body = unsafe { std::slice::from_raw_parts(segment_body.0, segment_body.1) };
obj.declare_with("all", Decl::function(), body.to_vec())?; obj.declare_with("all", Decl::function(), body.to_vec())?;
emit_dwarf(&mut obj, dwarf, &resolver)?; let frames = get_debug_frame_bytes(funcs, isa, frame_layouts)?;
emit_dwarf(&mut obj, dwarf, &resolver, frames)?;
// LLDB is too "magical" about mach-o, generating elf // LLDB is too "magical" about mach-o, generating elf
let mut bytes = obj.emit_as(BinaryFormat::Elf)?; let mut bytes = obj.emit_as(BinaryFormat::Elf)?;

View File

@@ -1,11 +1,12 @@
use super::address_transform::AddressTransform; use super::address_transform::AddressTransform;
use anyhow::{bail, Context, Error, Result}; use super::map_reg::map_reg;
use gimli::{self, write, Expression, Operation, Reader, ReaderOffset, Register, X86_64}; use anyhow::{Context, Error, Result};
use gimli::{self, write, Expression, Operation, Reader, ReaderOffset, X86_64};
use more_asserts::{assert_le, assert_lt}; use more_asserts::{assert_le, assert_lt};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use wasmtime_environ::entity::EntityRef; use wasmtime_environ::entity::EntityRef;
use wasmtime_environ::ir::{StackSlots, ValueLabel, ValueLabelsRanges, ValueLoc}; use wasmtime_environ::ir::{StackSlots, ValueLabel, ValueLabelsRanges, ValueLoc};
use wasmtime_environ::isa::{RegUnit, TargetIsa}; use wasmtime_environ::isa::TargetIsa;
use wasmtime_environ::wasm::{get_vmctx_value_label, DefinedFuncIndex}; use wasmtime_environ::wasm::{get_vmctx_value_label, DefinedFuncIndex};
use wasmtime_environ::ModuleMemoryOffset; use wasmtime_environ::ModuleMemoryOffset;
@@ -70,61 +71,6 @@ impl<'a> CompiledExpression<'a> {
} }
} }
fn map_reg(isa: &dyn TargetIsa, reg: RegUnit) -> Result<Register> {
// TODO avoid duplication with fde.rs
assert!(isa.name() == "x86" && isa.pointer_bits() == 64);
// Mapping from https://github.com/bytecodealliance/cranelift/pull/902 by @iximeow
const X86_GP_REG_MAP: [gimli::Register; 16] = [
X86_64::RAX,
X86_64::RCX,
X86_64::RDX,
X86_64::RBX,
X86_64::RSP,
X86_64::RBP,
X86_64::RSI,
X86_64::RDI,
X86_64::R8,
X86_64::R9,
X86_64::R10,
X86_64::R11,
X86_64::R12,
X86_64::R13,
X86_64::R14,
X86_64::R15,
];
const X86_XMM_REG_MAP: [gimli::Register; 16] = [
X86_64::XMM0,
X86_64::XMM1,
X86_64::XMM2,
X86_64::XMM3,
X86_64::XMM4,
X86_64::XMM5,
X86_64::XMM6,
X86_64::XMM7,
X86_64::XMM8,
X86_64::XMM9,
X86_64::XMM10,
X86_64::XMM11,
X86_64::XMM12,
X86_64::XMM13,
X86_64::XMM14,
X86_64::XMM15,
];
let reg_info = isa.register_info();
let bank = reg_info.bank_containing_regunit(reg).unwrap();
match bank.name {
"IntRegs" => {
// x86 GP registers have a weird mapping to DWARF registers, so we use a
// lookup table.
Ok(X86_GP_REG_MAP[(reg - bank.first_unit) as usize])
}
"FloatRegs" => Ok(X86_XMM_REG_MAP[(reg - bank.first_unit) as usize]),
bank_name => {
bail!("unsupported register bank: {}", bank_name);
}
}
}
fn translate_loc( fn translate_loc(
loc: ValueLoc, loc: ValueLoc,
frame_info: Option<&FunctionFrameInfo>, frame_info: Option<&FunctionFrameInfo>,

View File

@@ -0,0 +1,58 @@
use anyhow::{bail, Result};
use gimli::{Register, X86_64};
use wasmtime_environ::isa::{RegUnit, TargetIsa};
pub(crate) fn map_reg(isa: &dyn TargetIsa, reg: RegUnit) -> Result<Register> {
// TODO avoid duplication with fde.rs
assert!(isa.name() == "x86" && isa.pointer_bits() == 64);
// Mapping from https://github.com/bytecodealliance/cranelift/pull/902 by @iximeow
const X86_GP_REG_MAP: [Register; 16] = [
X86_64::RAX,
X86_64::RCX,
X86_64::RDX,
X86_64::RBX,
X86_64::RSP,
X86_64::RBP,
X86_64::RSI,
X86_64::RDI,
X86_64::R8,
X86_64::R9,
X86_64::R10,
X86_64::R11,
X86_64::R12,
X86_64::R13,
X86_64::R14,
X86_64::R15,
];
const X86_XMM_REG_MAP: [Register; 16] = [
X86_64::XMM0,
X86_64::XMM1,
X86_64::XMM2,
X86_64::XMM3,
X86_64::XMM4,
X86_64::XMM5,
X86_64::XMM6,
X86_64::XMM7,
X86_64::XMM8,
X86_64::XMM9,
X86_64::XMM10,
X86_64::XMM11,
X86_64::XMM12,
X86_64::XMM13,
X86_64::XMM14,
X86_64::XMM15,
];
let reg_info = isa.register_info();
let bank = reg_info.bank_containing_regunit(reg).unwrap();
match bank.name {
"IntRegs" => {
// x86 GP registers have a weird mapping to DWARF registers, so we use a
// lookup table.
Ok(X86_GP_REG_MAP[(reg - bank.first_unit) as usize])
}
"FloatRegs" => Ok(X86_XMM_REG_MAP[(reg - bank.first_unit) as usize]),
bank_name => {
bail!("unsupported register bank: {}", bank_name);
}
}
}

View File

@@ -14,11 +14,13 @@ use wasmtime_environ::isa::TargetIsa;
use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges}; use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges};
pub use address_transform::AddressTransform; pub use address_transform::AddressTransform;
pub(crate) use map_reg::map_reg;
mod address_transform; mod address_transform;
mod attr; mod attr;
mod expression; mod expression;
mod line_program; mod line_program;
mod map_reg;
mod range_info_builder; mod range_info_builder;
mod refs; mod refs;
mod simulate; mod simulate;

View File

@@ -1,6 +1,6 @@
use faerie::artifact::{Decl, SectionKind}; use faerie::artifact::{Decl, SectionKind};
use faerie::*; use faerie::*;
use gimli::write::{Address, Dwarf, EndianVec, Result, Sections, Writer}; use gimli::write::{Address, DebugFrame, Dwarf, EndianVec, FrameTable, Result, Sections, Writer};
use gimli::{RunTimeEndian, SectionId}; use gimli::{RunTimeEndian, SectionId};
#[derive(Clone)] #[derive(Clone)]
@@ -24,6 +24,7 @@ pub fn emit_dwarf(
artifact: &mut Artifact, artifact: &mut Artifact,
mut dwarf: Dwarf, mut dwarf: Dwarf,
symbol_resolver: &dyn SymbolResolver, symbol_resolver: &dyn SymbolResolver,
frames: Option<FrameTable>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let endian = RunTimeEndian::Little; let endian = RunTimeEndian::Little;
@@ -52,6 +53,30 @@ pub fn emit_dwarf(
} }
Ok(()) Ok(())
})?; })?;
if let Some(frames) = frames {
let mut debug_frame = DebugFrame::from(WriterRelocate::new(endian, symbol_resolver));
frames.write_debug_frame(&mut debug_frame).unwrap();
artifact.declare_with(
SectionId::DebugFrame.name(),
Decl::section(SectionKind::Debug),
debug_frame.writer.take(),
)?;
for reloc in &debug_frame.relocs {
artifact.link_with(
faerie::Link {
from: SectionId::DebugFrame.name(),
to: &reloc.name,
at: u64::from(reloc.offset),
},
faerie::Reloc::Debug {
size: reloc.size,
addend: reloc.addend as i32,
},
)?;
}
}
Ok(()) Ok(())
} }

View File

@@ -1,5 +1,6 @@
use crate::address_map::{ModuleAddressMap, ValueLabelsRanges}; use crate::address_map::{ModuleAddressMap, ValueLabelsRanges};
use crate::compilation::{Compilation, Relocations, Traps}; use crate::compilation::{Compilation, Relocations, Traps};
use crate::frame_layout::FrameLayouts;
use cranelift_codegen::ir; use cranelift_codegen::ir;
use cranelift_entity::PrimaryMap; use cranelift_entity::PrimaryMap;
use cranelift_wasm::DefinedFuncIndex; use cranelift_wasm::DefinedFuncIndex;
@@ -35,6 +36,7 @@ pub struct ModuleCacheData {
value_ranges: ValueLabelsRanges, value_ranges: ValueLabelsRanges,
stack_slots: PrimaryMap<DefinedFuncIndex, ir::StackSlots>, stack_slots: PrimaryMap<DefinedFuncIndex, ir::StackSlots>,
traps: Traps, traps: Traps,
frame_layouts: FrameLayouts,
} }
/// A type alias over the module cache data as a tuple. /// A type alias over the module cache data as a tuple.
@@ -45,6 +47,7 @@ pub type ModuleCacheDataTupleType = (
ValueLabelsRanges, ValueLabelsRanges,
PrimaryMap<DefinedFuncIndex, ir::StackSlots>, PrimaryMap<DefinedFuncIndex, ir::StackSlots>,
Traps, Traps,
FrameLayouts,
); );
struct Sha256Hasher(Sha256); struct Sha256Hasher(Sha256);
@@ -204,6 +207,7 @@ impl ModuleCacheData {
value_ranges: data.3, value_ranges: data.3,
stack_slots: data.4, stack_slots: data.4,
traps: data.5, traps: data.5,
frame_layouts: data.6,
} }
} }
@@ -215,6 +219,7 @@ impl ModuleCacheData {
self.value_ranges, self.value_ranges,
self.stack_slots, self.stack_slots,
self.traps, self.traps,
self.frame_layouts,
) )
} }
} }

View File

@@ -100,5 +100,6 @@ fn new_module_cache_data() -> Result<ModuleCacheDataTupleType, ()> {
PrimaryMap::new(), PrimaryMap::new(),
PrimaryMap::new(), PrimaryMap::new(),
PrimaryMap::new(), PrimaryMap::new(),
PrimaryMap::new(),
)) ))
} }

View File

@@ -6,6 +6,7 @@ use crate::compilation::{
Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Relocation, Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Relocation,
RelocationTarget, TrapInformation, RelocationTarget, TrapInformation,
}; };
use crate::frame_layout::FrameLayout;
use crate::func_environ::{get_func_name, FuncEnvironment}; use crate::func_environ::{get_func_name, FuncEnvironment};
use crate::module::{Module, ModuleLocal}; use crate::module::{Module, ModuleLocal};
use crate::module_environ::FunctionBodyData; use crate::module_environ::FunctionBodyData;
@@ -154,6 +155,38 @@ fn get_function_address_map<'data>(
} }
} }
fn get_frame_layout(
context: &Context,
isa: &dyn isa::TargetIsa,
) -> (
Box<[ir::FrameLayoutChange]>,
Box<[(usize, ir::FrameLayoutChange)]>,
) {
let func = &context.func;
assert!(func.frame_layout.is_some(), "expected func.frame_layout");
let mut blocks = func.layout.blocks().collect::<Vec<_>>();
blocks.sort_by_key(|b| func.offsets[*b]); // Ensure inst offsets always increase
let encinfo = isa.encoding_info();
let mut last_offset = 0;
let mut commands = Vec::new();
for b in blocks {
for (offset, inst, size) in func.inst_offsets(b, &encinfo) {
if let Some(cmds) = func.frame_layout.as_ref().unwrap().instructions.get(&inst) {
let address_offset = (offset + size) as usize;
assert!(last_offset < address_offset);
for cmd in cmds.iter() {
commands.push((address_offset, cmd.clone()));
}
last_offset = address_offset;
}
}
}
let initial = func.frame_layout.as_ref().unwrap().initial.clone();
(initial, commands.into_boxed_slice())
}
/// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR,
/// optimizing it and then translating to assembly. /// optimizing it and then translating to assembly.
pub struct Cranelift; pub struct Cranelift;
@@ -206,6 +239,7 @@ fn compile(
let mut value_ranges = PrimaryMap::with_capacity(function_body_inputs.len()); let mut value_ranges = PrimaryMap::with_capacity(function_body_inputs.len());
let mut stack_slots = PrimaryMap::with_capacity(function_body_inputs.len()); let mut stack_slots = PrimaryMap::with_capacity(function_body_inputs.len());
let mut traps = PrimaryMap::with_capacity(function_body_inputs.len()); let mut traps = PrimaryMap::with_capacity(function_body_inputs.len());
let mut frame_layouts = PrimaryMap::with_capacity(function_body_inputs.len());
function_body_inputs function_body_inputs
.into_iter() .into_iter()
@@ -254,6 +288,17 @@ fn compile(
None None
}; };
let frame_layout = if generate_debug_info {
let (initial_commands, commands) = get_frame_layout(&context, isa);
Some(FrameLayout {
call_conv: context.func.signature.call_conv,
initial_commands,
commands,
})
} else {
None
};
let ranges = if generate_debug_info { let ranges = if generate_debug_info {
let ranges = context.build_value_labels_ranges(isa).map_err(|error| { let ranges = context.build_value_labels_ranges(isa).map_err(|error| {
CompileError::Codegen(pretty_error(&context.func, Some(isa), error)) CompileError::Codegen(pretty_error(&context.func, Some(isa), error))
@@ -268,6 +313,7 @@ fn compile(
context.func.jt_offsets, context.func.jt_offsets,
reloc_sink.func_relocs, reloc_sink.func_relocs,
address_transform, address_transform,
frame_layout,
ranges, ranges,
context.func.stack_slots, context.func.stack_slots,
trap_sink.traps, trap_sink.traps,
@@ -282,6 +328,7 @@ fn compile(
func_jt_offsets, func_jt_offsets,
relocs, relocs,
address_transform, address_transform,
frame_layout,
ranges, ranges,
sss, sss,
function_traps, function_traps,
@@ -299,6 +346,9 @@ fn compile(
value_ranges.push(ranges.unwrap_or_default()); value_ranges.push(ranges.unwrap_or_default());
stack_slots.push(sss); stack_slots.push(sss);
traps.push(function_traps); traps.push(function_traps);
if let Some(frame_layout) = frame_layout {
frame_layouts.push(frame_layout);
}
}, },
); );
@@ -311,6 +361,7 @@ fn compile(
value_ranges, value_ranges,
stack_slots, stack_slots,
traps, traps,
frame_layouts,
)) ))
} }

View File

@@ -0,0 +1,21 @@
use cranelift_codegen::isa::CallConv;
use cranelift_entity::PrimaryMap;
use cranelift_wasm::DefinedFuncIndex;
use serde::{Deserialize, Serialize};
pub use cranelift_codegen::ir::FrameLayoutChange;
/// Frame layout information: call convention and
/// registers save/restore commands.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct FrameLayout {
/// Call convention.
pub call_conv: CallConv,
/// Frame default/initial commands.
pub initial_commands: Box<[FrameLayoutChange]>,
/// Frame commands at specific offset.
pub commands: Box<[(usize, FrameLayoutChange)]>,
}
/// Functions frame layouts.
pub type FrameLayouts = PrimaryMap<DefinedFuncIndex, FrameLayout>;

View File

@@ -27,6 +27,7 @@
mod address_map; mod address_map;
mod compilation; mod compilation;
mod data_structures; mod data_structures;
mod frame_layout;
mod func_environ; mod func_environ;
mod module; mod module;
mod module_environ; mod module_environ;
@@ -52,6 +53,7 @@ pub use crate::compilation::{
}; };
pub use crate::cranelift::Cranelift; pub use crate::cranelift::Cranelift;
pub use crate::data_structures::*; pub use crate::data_structures::*;
pub use crate::frame_layout::{FrameLayout, FrameLayoutChange, FrameLayouts};
pub use crate::func_environ::BuiltinFunctionIndex; pub use crate::func_environ::BuiltinFunctionIndex;
#[cfg(feature = "lightbeam")] #[cfg(feature = "lightbeam")]
pub use crate::lightbeam::Lightbeam; pub use crate::lightbeam::Lightbeam;

View File

@@ -70,6 +70,7 @@ impl crate::compilation::Compiler for Lightbeam {
ValueLabelsRanges::new(), ValueLabelsRanges::new(),
PrimaryMap::new(), PrimaryMap::new(),
Traps::new(), Traps::new(),
PrimaryMap::new(),
)) ))
} }
} }

View File

@@ -110,33 +110,40 @@ impl Compiler {
), ),
SetupError, SetupError,
> { > {
let (compilation, relocations, address_transform, value_ranges, stack_slots, traps) = let (
match self.strategy { compilation,
// For now, interpret `Auto` as `Cranelift` since that's the most stable relocations,
// implementation. address_transform,
CompilationStrategy::Auto | CompilationStrategy::Cranelift => { value_ranges,
wasmtime_environ::cranelift::Cranelift::compile_module( stack_slots,
module, traps,
module_translation, frame_layouts,
function_body_inputs, ) = match self.strategy {
&*self.isa, // For now, interpret `Auto` as `Cranelift` since that's the most stable
debug_data.is_some(), // implementation.
&self.cache_config, CompilationStrategy::Auto | CompilationStrategy::Cranelift => {
) wasmtime_environ::cranelift::Cranelift::compile_module(
} module,
#[cfg(feature = "lightbeam")] module_translation,
CompilationStrategy::Lightbeam => { function_body_inputs,
wasmtime_environ::lightbeam::Lightbeam::compile_module( &*self.isa,
module, debug_data.is_some(),
module_translation, &self.cache_config,
function_body_inputs, )
&*self.isa,
debug_data.is_some(),
&self.cache_config,
)
}
} }
.map_err(SetupError::Compile)?; #[cfg(feature = "lightbeam")]
CompilationStrategy::Lightbeam => {
wasmtime_environ::lightbeam::Lightbeam::compile_module(
module,
module_translation,
function_body_inputs,
&*self.isa,
debug_data.is_some(),
&self.cache_config,
)
}
}
.map_err(SetupError::Compile)?;
let allocated_functions = let allocated_functions =
allocate_functions(&mut self.code_memory, &compilation).map_err(|message| { allocate_functions(&mut self.code_memory, &compilation).map_err(|message| {
@@ -179,6 +186,7 @@ impl Compiler {
&module_vmctx_info, &module_vmctx_info,
&address_transform, &address_transform,
&value_ranges, &value_ranges,
&frame_layouts,
&funcs, &funcs,
) )
.map_err(SetupError::DebugInfo)?; .map_err(SetupError::DebugInfo)?;

View File

@@ -79,30 +79,37 @@ pub fn compile_to_obj(
}; };
// TODO: use the traps information // TODO: use the traps information
let (compilation, relocations, address_transform, value_ranges, stack_slots, _traps) = let (
match strategy { compilation,
Strategy::Auto | Strategy::Cranelift => Cranelift::compile_module( relocations,
&module, address_transform,
&module_translation, value_ranges,
lazy_function_body_inputs, stack_slots,
&*isa, _traps,
debug_info, frame_layouts,
cache_config, ) = match strategy {
), Strategy::Auto | Strategy::Cranelift => Cranelift::compile_module(
#[cfg(feature = "lightbeam")] &module,
Strategy::Lightbeam => Lightbeam::compile_module( &module_translation,
&module, lazy_function_body_inputs,
&module_translation, &*isa,
lazy_function_body_inputs, debug_info,
&*isa, cache_config,
debug_info, ),
cache_config, #[cfg(feature = "lightbeam")]
), Strategy::Lightbeam => Lightbeam::compile_module(
#[cfg(not(feature = "lightbeam"))] &module,
Strategy::Lightbeam => bail!("lightbeam support not enabled"), &module_translation,
other => bail!("unsupported compilation strategy {:?}", other), lazy_function_body_inputs,
} &*isa,
.context("failed to compile module")?; debug_info,
cache_config,
),
#[cfg(not(feature = "lightbeam"))]
Strategy::Lightbeam => bail!("lightbeam support not enabled"),
other => bail!("unsupported compilation strategy {:?}", other),
}
.context("failed to compile module")?;
if compilation.is_empty() { if compilation.is_empty() {
bail!("no functions were found/compiled"); bail!("no functions were found/compiled");
@@ -144,6 +151,7 @@ pub fn compile_to_obj(
&debug_data, &debug_data,
&address_transform, &address_transform,
&value_ranges, &value_ranges,
&frame_layouts,
) )
.context("failed to emit debug sections")?; .context("failed to emit debug sections")?;
} }