Skip to content

Commit

Permalink
Use initial_commands for CIE
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik committed Apr 9, 2019
1 parent 2bf413f commit 4d6d446
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 87 deletions.
115 changes: 69 additions & 46 deletions wasmtime-debug/src/frame.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#![allow(non_upper_case_globals)]

use cranelift_codegen::isa::{CallConv, RegUnit, TargetIsa};
use cranelift_codegen::ir::FrameLayoutChange;
use cranelift_entity::EntityRef;
use cranelift_wasm::DefinedFuncIndex;
use std::collections::HashMap;
use std::vec::Vec;
use wasmtime_environ::{FrameLayoutCommand, FrameLayouts};
use wasmtime_environ::FrameLayouts;

use gimli::write::{
Address, CallFrameInstruction, CommonInformationEntry as CIEEntry, Error,
Expand Down Expand Up @@ -42,7 +43,6 @@ fn map_reg(isa: &TargetIsa, reg: RegUnit) -> Register {
"%r13" => X86_64::R13,
"%r14" => X86_64::R14,
"%r15" => X86_64::R15,
"%r16" => X86_64::RA,
"%xmm0" => X86_64::XMM0,
"%xmm1" => X86_64::XMM1,
"%xmm2" => X86_64::XMM2,
Expand All @@ -58,6 +58,39 @@ fn map_reg(isa: &TargetIsa, reg: RegUnit) -> Register {
}
}

fn to_cfi(isa: &TargetIsa, change: &FrameLayoutChange, cfa_def_reg: &mut Register, cfa_def_offset: &mut i32) -> Option<CallFrameInstruction> {
Some(match change {
FrameLayoutChange::CallFrameAddressAt { reg, offset } => {
let mapped = map_reg(isa, *reg);
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 = map_reg(isa, *reg);
CallFrameInstruction::Offset(mapped, cfa_offset)
}
FrameLayoutChange::RaAt { cfa_offset } => {
assert!(cfa_offset % -8 == 0);
let cfa_offset = *cfa_offset as i32;
CallFrameInstruction::Offset(X86_64::RA, cfa_offset)
}
})
}

pub fn get_debug_frame_bytes(
funcs: &Vec<(*const u8, usize)>,
isa: &TargetIsa,
Expand All @@ -82,19 +115,38 @@ pub fn get_debug_frame_bytes(

let mut frames = FrameTable::default();

let mut cie = CIEEntry::new(
encoding,
/* code_alignment_factor = */ 1,
/* data_alignment_factor = */ -8,
/* return_address_register = */ X86_64::RA,
);
cie.add_instruction(CallFrameInstruction::Cfa(X86_64::RSP, 8));
cie.add_instruction(CallFrameInstruction::Offset(X86_64::RA, -8));
let cie_id = frames.add_cie(cie);
let mut cached_cies = HashMap::new();

for (i, f) in funcs.into_iter().enumerate() {
let mut cfa_def_reg = X86_64::RSP;
let mut cfa_def_offset = 8i32;
let layout = &layouts[DefinedFuncIndex::new(i)];

// 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(
Expand All @@ -105,39 +157,10 @@ pub fn get_debug_frame_bytes(
f_len,
);

let layout = &layouts[DefinedFuncIndex::new(i)];
let mut offset = 0;
for cmd in layout.commands.into_iter() {
let instr = match cmd {
FrameLayoutCommand::MoveLocationBy(delta) => {
offset += *delta as u32;
continue;
}
FrameLayoutCommand::CallFrameAddressAt { reg, offset } => {
let mapped = map_reg(isa, *reg);
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 {
continue; // no instructions
}
}
FrameLayoutCommand::RegAt { reg, cfa_offset } => {
assert!(cfa_offset % -8 == 0);
let cfa_offset = *cfa_offset as i32;
let mapped = map_reg(isa, *reg);
CallFrameInstruction::Offset(mapped, cfa_offset)
}
};
fde.add_instruction(offset, instr);
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);
Expand Down
26 changes: 4 additions & 22 deletions wasmtime-environ/src/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmError};
use std::boxed::Box;
use std::vec::Vec;

pub use cranelift_codegen::ir::FrameLayoutChange;

/// The result of compiling a WebAssembly module's functions.
#[derive(Debug)]
pub struct Compilation {
Expand Down Expand Up @@ -98,32 +100,12 @@ pub struct FunctionAddressTransform {
/// Function AddressTransforms collection.
pub type AddressTransforms = PrimaryMap<DefinedFuncIndex, FunctionAddressTransform>;

/// TODO
#[derive(Debug)]
pub enum FrameLayoutCommand {
/// TODO
MoveLocationBy(usize),
/// TODO
CallFrameAddressAt {
/// TODO
reg: isa::RegUnit,
/// TODO
offset: isize,
},
/// TODO
RegAt {
/// TODO
reg: isa::RegUnit,
/// TODO
cfa_offset: isize,
},
}

/// TODO
#[derive(Debug)]
pub struct FrameLayout {
pub call_conv: isa::CallConv,
pub commands: Box<[FrameLayoutCommand]>,
pub initial_commands: Box<[FrameLayoutChange]>,
pub commands: Box<[(usize, FrameLayoutChange)]>,
}

/// TODO
Expand Down
28 changes: 10 additions & 18 deletions wasmtime-environ/src/cranelift.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Support for compiling with Cranelift.
use crate::compilation::{
AddressTransforms, Compilation, CompileError, FrameLayout, FrameLayoutCommand, FrameLayouts,
AddressTransforms, Compilation, CompileError, FrameLayout, FrameLayouts,
FunctionAddressTransform, InstructionAddressTransform, Relocation, RelocationTarget,
Relocations,
};
Expand All @@ -20,6 +20,7 @@ use cranelift_entity::PrimaryMap;
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use std::vec::Vec;
use std::boxed::Box;

/// Implementation of a relocation sink that just saves all the information for later
struct RelocSink {
Expand Down Expand Up @@ -110,38 +111,28 @@ fn get_address_transform(
result
}

fn get_frame_layout(context: &Context, isa: &isa::TargetIsa) -> Vec<FrameLayoutCommand> {
fn get_frame_layout(context: &Context, isa: &isa::TargetIsa) -> (Box<[ir::FrameLayoutChange]>, Box<[(usize, ir::FrameLayoutChange)]>) {
let func = &context.func;
let mut ebbs = func.layout.ebbs().collect::<Vec<_>>();
ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase

let encinfo = isa.encoding_info();
let mut last_offset = 0;
let mut result = Vec::new();
let mut commands = Vec::new();
for ebb in ebbs {
for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) {
if let Some(cmds) = func.frame_layout.instructions.get(&inst) {
let address_offset = (offset + size) as usize;
assert!(last_offset < address_offset);
result.push(FrameLayoutCommand::MoveLocationBy(
address_offset - last_offset,
));
for c in cmds.iter() {
result.push(match *c {
ir::FrameLayoutChange::CallFrameAddressAt { reg, offset } => {
FrameLayoutCommand::CallFrameAddressAt { reg, offset }
}
ir::FrameLayoutChange::RegAt { reg, cfa_offset } => {
FrameLayoutCommand::RegAt { reg, cfa_offset }
}
ir::FrameLayoutChange::RaAt { .. } => panic!("Unexpected frame change"),
});
for cmd in cmds.iter() {
commands.push((address_offset, cmd.clone()));
}
last_offset = address_offset;
}
}
}
result
let initial = func.frame_layout.initial.clone();
(initial, commands.into_boxed_slice())
}

/// Compile the module using Cranelift, producing a compilation result with
Expand Down Expand Up @@ -197,9 +188,10 @@ pub fn compile_module<'data, 'module>(
};

let frame_layout = if generate_debug_info {
let commands = get_frame_layout(&context, isa).into_boxed_slice();
let (initial_commands, commands) = get_frame_layout(&context, isa);
Some(FrameLayout {
call_conv: context.func.signature.call_conv,
initial_commands,
commands,
})
} else {
Expand Down
2 changes: 1 addition & 1 deletion wasmtime-environ/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ mod vmoffsets;
pub mod cranelift;

pub use crate::compilation::{
AddressTransforms, Compilation, CompileError, FrameLayoutCommand, FrameLayouts,
AddressTransforms, Compilation, CompileError, FrameLayouts,
InstructionAddressTransform, Relocation, RelocationTarget, Relocations,
};
pub use crate::module::{
Expand Down

0 comments on commit 4d6d446

Please sign in to comment.