Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove dependency on libgcc-dw2-1.dll from win32 executables. #29177

Merged
merged 10 commits into from
Nov 1, 2015
Next Next commit
Revisit implementation of custom unwind resume;
Rather than injecting a local `_Unwind_Resume` into the current translation unit,
just replace `resume` instruction with a direct call the the `eh_unwind_resume` lang item.
This is likely to be more robust in the face of future LLVM changes, and also allows us to delegate
work back to libgcc's `_Unwind_Resume`.
  • Loading branch information
vadimcn committed Oct 19, 2015
commit 1da466253c1fe6491f330a4ae5aa56da950928bf
13 changes: 13 additions & 0 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,19 @@ pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
Call(cx, lifetime_end, &[C_u64(ccx, size), ptr], None, DebugLoc::None);
}

// Generates code for resumption of unwind at the end of a landing pad.
pub fn trans_unwind_resume(bcx: Block, lpval: ValueRef) {
if !bcx.sess().target.target.options.custom_unwind_resume {
Resume(bcx, lpval);
} else {
let exc_ptr = ExtractValue(bcx, lpval, 0);
let llunwresume = bcx.fcx.eh_unwind_resume();
Call(bcx, llunwresume, &[exc_ptr], None, DebugLoc::None);
Unreachable(bcx);
}
}


pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
let _icx = push_ctxt("call_memcpy");
let ccx = cx.ccx();
Expand Down
4 changes: 1 addition & 3 deletions src/librustc_trans/trans/cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
"create_landing_pad() should have set this");
let lp = build::Load(prev_bcx, personality);
base::call_lifetime_end(prev_bcx, personality);
build::Resume(prev_bcx, lp);
base::trans_unwind_resume(prev_bcx, lp);
prev_llbb = prev_bcx.llbb;
break;
}
Expand Down Expand Up @@ -845,8 +845,6 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx

debug!("get_or_create_landing_pad");

self.inject_unwind_resume_hook();

// Check if a landing pad block exists; if not, create one.
{
let mut scopes = self.scopes.borrow_mut();
Expand Down
68 changes: 24 additions & 44 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,53 +561,33 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
}
}

/// By default, LLVM lowers `resume` instructions into calls to `_Unwind_Resume`
/// defined in libgcc, however, unlike personality routines, there is no easy way to
/// override that symbol. This method injects a local-scoped `_Unwind_Resume` function
/// which immediately defers to the user-defined `eh_unwind_resume` lang item.
pub fn inject_unwind_resume_hook(&self) {
let ccx = self.ccx;
if !ccx.sess().target.target.options.custom_unwind_resume ||
ccx.unwind_resume_hooked().get() {
return;
}

let new_resume = match ccx.tcx().lang_items.eh_unwind_resume() {
Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0), &self.param_substs).val,
// Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined,
// otherwise declares it as an external funtion.
pub fn eh_unwind_resume(&self) -> ValueRef {
use trans::attributes;
assert!(self.ccx.sess().target.target.options.custom_unwind_resume);
match self.ccx.tcx().lang_items.eh_unwind_resume() {
Some(def_id) => {
callee::trans_fn_ref(self.ccx, def_id, ExprId(0),
self.param_substs).val
}
None => {
let fty = Type::variadic_func(&[], &Type::void(self.ccx));
declare::declare_cfn(self.ccx, "rust_eh_unwind_resume", fty,
self.ccx.tcx().mk_nil())
let mut unwresume = self.ccx.eh_unwind_resume().borrow_mut();
match *unwresume {
Some(llfn) => llfn,
None => {
let fty = Type::func(&[Type::i8p(self.ccx)], &Type::void(self.ccx));
let llfn = declare::declare_fn(self.ccx,
"rust_eh_unwind_resume",
llvm::CCallConv,
fty, ty::FnDiverging);
attributes::unwind(llfn, true);
*unwresume = Some(llfn);
llfn
}
}
}
};

unsafe {
let resume_type = Type::func(&[Type::i8(ccx).ptr_to()], &Type::void(ccx));
let old_resume = llvm::LLVMAddFunction(ccx.llmod(),
"_Unwind_Resume\0".as_ptr() as *const _,
resume_type.to_ref());
llvm::SetLinkage(old_resume, llvm::InternalLinkage);
let llbb = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(),
old_resume,
"\0".as_ptr() as *const _);
let builder = ccx.builder();
builder.position_at_end(llbb);
builder.call(new_resume, &[llvm::LLVMGetFirstParam(old_resume)], None);
builder.unreachable(); // it should never return

// Until DwarfEHPrepare pass has run, _Unwind_Resume is not referenced by any live code
// and is subject to dead code elimination. Here we add _Unwind_Resume to @llvm.globals
// to prevent that.
let i8p_ty = Type::i8p(ccx);
let used_ty = Type::array(&i8p_ty, 1);
let used = llvm::LLVMAddGlobal(ccx.llmod(), used_ty.to_ref(),
"llvm.used\0".as_ptr() as *const _);
let old_resume = llvm::LLVMConstBitCast(old_resume, i8p_ty.to_ref());
llvm::LLVMSetInitializer(used, C_array(i8p_ty, &[old_resume]));
llvm::SetLinkage(used, llvm::AppendingLinkage);
llvm::LLVMSetSection(used, "llvm.metadata\0".as_ptr() as *const _)
}
ccx.unwind_resume_hooked().set(true);
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/librustc_trans/trans/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ pub struct LocalCrateContext<'tcx> {
dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>,

eh_personality: RefCell<Option<ValueRef>>,
eh_unwind_resume: RefCell<Option<ValueRef>>,
rust_try_fn: RefCell<Option<ValueRef>>,
unwind_resume_hooked: Cell<bool>,

intrinsics: RefCell<FnvHashMap<&'static str, ValueRef>>,

Expand Down Expand Up @@ -466,8 +466,8 @@ impl<'tcx> LocalCrateContext<'tcx> {
closure_vals: RefCell::new(FnvHashMap()),
dbg_cx: dbg_cx,
eh_personality: RefCell::new(None),
eh_unwind_resume: RefCell::new(None),
rust_try_fn: RefCell::new(None),
unwind_resume_hooked: Cell::new(false),
intrinsics: RefCell::new(FnvHashMap()),
n_llvm_insns: Cell::new(0),
trait_cache: RefCell::new(FnvHashMap()),
Expand Down Expand Up @@ -728,12 +728,12 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local.eh_personality
}

pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
&self.local.rust_try_fn
pub fn eh_unwind_resume<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
&self.local.eh_unwind_resume
}

pub fn unwind_resume_hooked<'a>(&'a self) -> &'a Cell<bool> {
&self.local.unwind_resume_hooked
pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
&self.local.rust_try_fn
}

fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,7 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// The "catch-resume" block is where we're running this landing pad but
// we actually need to not catch the exception, so just resume the
// exception to return.
Resume(catch_resume, vals);
trans_unwind_resume(catch_resume, vals);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This in theory isn't necessary, right? (it's only used for MSVC targets which don't have custom_unwind_resume set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, true. Still, it's probably a good thing to centralize checking of the custom_unwind_resume flag?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah makes sense, thanks for the clarification!


// On the successful branch we just return null.
Ret(then, C_null(Type::i8p(ccx)), dloc);
Expand Down