Skip to content

Commit 1da4662

Browse files
committed
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`.
1 parent 4af89fe commit 1da4662

File tree

5 files changed

+45
-54
lines changed

5 files changed

+45
-54
lines changed

src/librustc_trans/trans/base.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,19 @@ pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
944944
Call(cx, lifetime_end, &[C_u64(ccx, size), ptr], None, DebugLoc::None);
945945
}
946946

947+
// Generates code for resumption of unwind at the end of a landing pad.
948+
pub fn trans_unwind_resume(bcx: Block, lpval: ValueRef) {
949+
if !bcx.sess().target.target.options.custom_unwind_resume {
950+
Resume(bcx, lpval);
951+
} else {
952+
let exc_ptr = ExtractValue(bcx, lpval, 0);
953+
let llunwresume = bcx.fcx.eh_unwind_resume();
954+
Call(bcx, llunwresume, &[exc_ptr], None, DebugLoc::None);
955+
Unreachable(bcx);
956+
}
957+
}
958+
959+
947960
pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
948961
let _icx = push_ctxt("call_memcpy");
949962
let ccx = cx.ccx();

src/librustc_trans/trans/cleanup.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
732732
"create_landing_pad() should have set this");
733733
let lp = build::Load(prev_bcx, personality);
734734
base::call_lifetime_end(prev_bcx, personality);
735-
build::Resume(prev_bcx, lp);
735+
base::trans_unwind_resume(prev_bcx, lp);
736736
prev_llbb = prev_bcx.llbb;
737737
break;
738738
}
@@ -845,8 +845,6 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
845845

846846
debug!("get_or_create_landing_pad");
847847

848-
self.inject_unwind_resume_hook();
849-
850848
// Check if a landing pad block exists; if not, create one.
851849
{
852850
let mut scopes = self.scopes.borrow_mut();

src/librustc_trans/trans/common.rs

Lines changed: 24 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -561,53 +561,33 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
561561
}
562562
}
563563

564-
/// By default, LLVM lowers `resume` instructions into calls to `_Unwind_Resume`
565-
/// defined in libgcc, however, unlike personality routines, there is no easy way to
566-
/// override that symbol. This method injects a local-scoped `_Unwind_Resume` function
567-
/// which immediately defers to the user-defined `eh_unwind_resume` lang item.
568-
pub fn inject_unwind_resume_hook(&self) {
569-
let ccx = self.ccx;
570-
if !ccx.sess().target.target.options.custom_unwind_resume ||
571-
ccx.unwind_resume_hooked().get() {
572-
return;
573-
}
574-
575-
let new_resume = match ccx.tcx().lang_items.eh_unwind_resume() {
576-
Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0), &self.param_substs).val,
564+
// Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined,
565+
// otherwise declares it as an external funtion.
566+
pub fn eh_unwind_resume(&self) -> ValueRef {
567+
use trans::attributes;
568+
assert!(self.ccx.sess().target.target.options.custom_unwind_resume);
569+
match self.ccx.tcx().lang_items.eh_unwind_resume() {
570+
Some(def_id) => {
571+
callee::trans_fn_ref(self.ccx, def_id, ExprId(0),
572+
self.param_substs).val
573+
}
577574
None => {
578-
let fty = Type::variadic_func(&[], &Type::void(self.ccx));
579-
declare::declare_cfn(self.ccx, "rust_eh_unwind_resume", fty,
580-
self.ccx.tcx().mk_nil())
575+
let mut unwresume = self.ccx.eh_unwind_resume().borrow_mut();
576+
match *unwresume {
577+
Some(llfn) => llfn,
578+
None => {
579+
let fty = Type::func(&[Type::i8p(self.ccx)], &Type::void(self.ccx));
580+
let llfn = declare::declare_fn(self.ccx,
581+
"rust_eh_unwind_resume",
582+
llvm::CCallConv,
583+
fty, ty::FnDiverging);
584+
attributes::unwind(llfn, true);
585+
*unwresume = Some(llfn);
586+
llfn
587+
}
588+
}
581589
}
582-
};
583-
584-
unsafe {
585-
let resume_type = Type::func(&[Type::i8(ccx).ptr_to()], &Type::void(ccx));
586-
let old_resume = llvm::LLVMAddFunction(ccx.llmod(),
587-
"_Unwind_Resume\0".as_ptr() as *const _,
588-
resume_type.to_ref());
589-
llvm::SetLinkage(old_resume, llvm::InternalLinkage);
590-
let llbb = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(),
591-
old_resume,
592-
"\0".as_ptr() as *const _);
593-
let builder = ccx.builder();
594-
builder.position_at_end(llbb);
595-
builder.call(new_resume, &[llvm::LLVMGetFirstParam(old_resume)], None);
596-
builder.unreachable(); // it should never return
597-
598-
// Until DwarfEHPrepare pass has run, _Unwind_Resume is not referenced by any live code
599-
// and is subject to dead code elimination. Here we add _Unwind_Resume to @llvm.globals
600-
// to prevent that.
601-
let i8p_ty = Type::i8p(ccx);
602-
let used_ty = Type::array(&i8p_ty, 1);
603-
let used = llvm::LLVMAddGlobal(ccx.llmod(), used_ty.to_ref(),
604-
"llvm.used\0".as_ptr() as *const _);
605-
let old_resume = llvm::LLVMConstBitCast(old_resume, i8p_ty.to_ref());
606-
llvm::LLVMSetInitializer(used, C_array(i8p_ty, &[old_resume]));
607-
llvm::SetLinkage(used, llvm::AppendingLinkage);
608-
llvm::LLVMSetSection(used, "llvm.metadata\0".as_ptr() as *const _)
609590
}
610-
ccx.unwind_resume_hooked().set(true);
611591
}
612592
}
613593

src/librustc_trans/trans/context.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ pub struct LocalCrateContext<'tcx> {
146146
dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>,
147147

148148
eh_personality: RefCell<Option<ValueRef>>,
149+
eh_unwind_resume: RefCell<Option<ValueRef>>,
149150
rust_try_fn: RefCell<Option<ValueRef>>,
150-
unwind_resume_hooked: Cell<bool>,
151151

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

@@ -466,8 +466,8 @@ impl<'tcx> LocalCrateContext<'tcx> {
466466
closure_vals: RefCell::new(FnvHashMap()),
467467
dbg_cx: dbg_cx,
468468
eh_personality: RefCell::new(None),
469+
eh_unwind_resume: RefCell::new(None),
469470
rust_try_fn: RefCell::new(None),
470-
unwind_resume_hooked: Cell::new(false),
471471
intrinsics: RefCell::new(FnvHashMap()),
472472
n_llvm_insns: Cell::new(0),
473473
trait_cache: RefCell::new(FnvHashMap()),
@@ -728,12 +728,12 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
728728
&self.local.eh_personality
729729
}
730730

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

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

739739
fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> {

src/librustc_trans/trans/intrinsic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1315,7 +1315,7 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
13151315
// The "catch-resume" block is where we're running this landing pad but
13161316
// we actually need to not catch the exception, so just resume the
13171317
// exception to return.
1318-
Resume(catch_resume, vals);
1318+
trans_unwind_resume(catch_resume, vals);
13191319

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

0 commit comments

Comments
 (0)