Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Refactor unwind; add FDE support. (#1320)
Browse files Browse the repository at this point in the history
* Refactor unwind

* add FDE support

* use sink directly in emit functions

* pref off all unwinding generation with feature
  • Loading branch information
yurydelendik committed Jan 13, 2020
1 parent 1e760a5 commit e6e6715
Show file tree
Hide file tree
Showing 14 changed files with 1,000 additions and 55 deletions.
6 changes: 5 additions & 1 deletion cranelift-codegen/Cargo.toml
Expand Up @@ -20,6 +20,7 @@ hashbrown = { version = "0.6", optional = true }
target-lexicon = "0.10"
log = { version = "0.4.6", default-features = false }
serde = { version = "1.0.94", features = ["derive"], optional = true }
gimli = { version = "0.19.0", default-features = false, features = ["write"], optional = true }
smallvec = { version = "1.0.0" }
thiserror = "1.0.4"
byteorder = { version = "1.3.2", default-features = false }
Expand All @@ -32,7 +33,7 @@ byteorder = { version = "1.3.2", default-features = false }
cranelift-codegen-meta = { path = "meta", version = "0.54.0" }

[features]
default = ["std", "basic-blocks"]
default = ["std", "basic-blocks", "unwind"]

# The "std" feature enables use of libstd. The "core" feature enables use
# of some minimal std-like replacement libraries. At least one of these two
Expand All @@ -47,6 +48,9 @@ core = ["hashbrown"]
# can significantly increase the size of the library.
testing_hooks = []

# This enables unwind info generation functionality.
unwind = ["gimli"]

# ISA targets for which we should build.
# If no ISA targets are explicitly enabled, the ISA target for the host machine is enabled.
x86 = []
Expand Down
30 changes: 30 additions & 0 deletions cranelift-codegen/src/binemit/mod.rs
Expand Up @@ -155,6 +155,36 @@ pub trait CodeSink {
fn add_stackmap(&mut self, _: &[Value], _: &Function, _: &dyn TargetIsa);
}

/// Type of the frame unwind information.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum FrameUnwindKind {
/// Windows fastcall unwinding (as in .pdata).
Fastcall,
/// FDE entry for libunwind (similar to .eh_frame format).
Libunwind,
}

/// Offset in frame unwind information buffer.
pub type FrameUnwindOffset = usize;

/// Sink for frame unwind information.
pub trait FrameUnwindSink {
/// Get the current position.
fn len(&self) -> FrameUnwindOffset;

/// Add bytes to the code section.
fn bytes(&mut self, _: &[u8]);

/// Reserves bytes in the buffer.
fn reserve(&mut self, _len: usize) {}

/// Add a relocation entry.
fn reloc(&mut self, _: Reloc, _: FrameUnwindOffset);

/// Specified offset to main structure.
fn set_entry_offset(&mut self, _: FrameUnwindOffset);
}

/// Report a bad encoding error.
#[cold]
pub fn bad_encoding(func: &Function, inst: Inst) -> ! {
Expand Down
13 changes: 9 additions & 4 deletions cranelift-codegen/src/context.rs
Expand Up @@ -10,8 +10,8 @@
//! single ISA instance.

use crate::binemit::{
relax_branches, shrink_instructions, CodeInfo, MemoryCodeSink, RelocSink, StackmapSink,
TrapSink,
relax_branches, shrink_instructions, CodeInfo, FrameUnwindKind, FrameUnwindSink,
MemoryCodeSink, RelocSink, StackmapSink, TrapSink,
};
use crate::dce::do_dce;
use crate::dominator_tree::DominatorTree;
Expand Down Expand Up @@ -201,8 +201,13 @@ impl Context {
///
/// Only some calling conventions (e.g. Windows fastcall) will have unwind information.
/// This is a no-op if the function has no unwind information.
pub fn emit_unwind_info(&self, isa: &dyn TargetIsa, mem: &mut Vec<u8>) {
isa.emit_unwind_info(&self.func, mem);
pub fn emit_unwind_info(
&self,
isa: &dyn TargetIsa,
kind: FrameUnwindKind,
sink: &mut dyn FrameUnwindSink,
) {
isa.emit_unwind_info(&self.func, kind, sink);
}

/// Run the verifier on the function.
Expand Down
5 changes: 5 additions & 0 deletions cranelift-codegen/src/ir/function.rs
Expand Up @@ -253,6 +253,11 @@ impl Function {
/// Starts collection of debug information.
pub fn collect_debug_info(&mut self) {
self.dfg.collect_debug_info();
self.collect_frame_layout_info();
}

/// Starts collection of frame layout information.
pub fn collect_frame_layout_info(&mut self) {
self.frame_layout = Some(FrameLayout::new());
}

Expand Down
8 changes: 6 additions & 2 deletions cranelift-codegen/src/isa/mod.rs
Expand Up @@ -63,7 +63,6 @@ use crate::settings::SetResult;
use crate::timing;
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt;
use target_lexicon::{triple, Architecture, PointerWidth, Triple};
use thiserror::Error;
Expand Down Expand Up @@ -382,7 +381,12 @@ pub trait TargetIsa: fmt::Display + Send + Sync {
/// Emit unwind information for the given function.
///
/// Only some calling conventions (e.g. Windows fastcall) will have unwind information.
fn emit_unwind_info(&self, _func: &ir::Function, _mem: &mut Vec<u8>) {
fn emit_unwind_info(
&self,
_func: &ir::Function,
_kind: binemit::FrameUnwindKind,
_sink: &mut dyn binemit::FrameUnwindSink,
) {
// No-op by default
}
}
31 changes: 25 additions & 6 deletions cranelift-codegen/src/isa/x86/abi.rs
@@ -1,10 +1,15 @@
//! x86 ABI implementation.

use super::super::settings as shared_settings;
#[cfg(feature = "unwind")]
use super::fde::emit_fde;
use super::registers::{FPR, GPR, RU};
use super::settings as isa_settings;
#[cfg(feature = "unwind")]
use super::unwind::UnwindInfo;
use crate::abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion};
#[cfg(feature = "unwind")]
use crate::binemit::{FrameUnwindKind, FrameUnwindSink};
use crate::cursor::{Cursor, CursorPosition, EncCursor};
use crate::ir;
use crate::ir::immediates::Imm64;
Expand All @@ -18,7 +23,6 @@ use crate::regalloc::RegisterSet;
use crate::result::CodegenResult;
use crate::stack_layout::layout_stack;
use alloc::borrow::Cow;
use alloc::vec::Vec;
use core::i32;
use std::boxed::Box;
use target_lexicon::{PointerWidth, Triple};
Expand Down Expand Up @@ -947,10 +951,25 @@ fn insert_common_epilogue(
}
}

pub fn emit_unwind_info(func: &ir::Function, isa: &dyn TargetIsa, mem: &mut Vec<u8>) {
// Assumption: RBP is being used as the frame pointer
// In the future, Windows fastcall codegen should usually omit the frame pointer
if let Some(info) = UnwindInfo::try_from_func(func, isa, Some(RU::rbp.into())) {
info.emit(mem);
#[cfg(feature = "unwind")]
pub fn emit_unwind_info(
func: &ir::Function,
isa: &dyn TargetIsa,
kind: FrameUnwindKind,
sink: &mut dyn FrameUnwindSink,
) {
match kind {
FrameUnwindKind::Fastcall => {
// Assumption: RBP is being used as the frame pointer
// In the future, Windows fastcall codegen should usually omit the frame pointer
if let Some(info) = UnwindInfo::try_from_func(func, isa, Some(RU::rbp.into())) {
info.emit(sink);
}
}
FrameUnwindKind::Libunwind => {
if func.frame_layout.is_some() {
emit_fde(func, isa, sink);
}
}
}
}

0 comments on commit e6e6715

Please sign in to comment.