Skip to content

Return unwind #4342

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 63 additions & 10 deletions src/libcore/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,38 @@ pub struct Closure {
env: *(),
}

pub mod rustrt {
use libc::{c_char, size_t};

pub extern {
#[rust_stack]
unsafe fn rust_upcall_fail(unwind: bool, expr: *c_char,
file: *c_char, line: size_t);
}
}

#[cfg(stage0)]
pub mod rusti {
#[abi = "rust-intrinsic"]
pub extern {
extern {
fn get_tydesc<T>() -> *();
fn size_of<T>() -> uint;
fn pref_align_of<T>() -> uint;
fn min_align_of<T>() -> uint;
}
}

pub mod rustrt {
use libc::{c_char, size_t};

pub extern {
#[rust_stack]
unsafe fn rust_upcall_fail(expr: *c_char,
file: *c_char,
line: size_t);
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
pub mod rusti {
#[abi = "rust-intrinsic"]
extern {
fn get_tydesc<T>() -> *();
fn size_of<T>() -> uint;
fn pref_align_of<T>() -> uint;
fn min_align_of<T>() -> uint;
fn set_retcode_fail();
}
}

Expand Down Expand Up @@ -134,7 +148,17 @@ pub pure fn log_str<T>(t: &T) -> ~str {
}
}


#[cfg(return_unwind)]
const do_throw:bool = false;

#[cfg(stage0)]
#[cfg(throw_unwind)]
const do_throw:bool = true;

/** Initiate task failure */
#[cfg(stage0)]
#[cfg(throw_unwind)]
pub pure fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
do str::as_buf(msg) |msg_buf, _msg_len| {
do str::as_buf(file) |file_buf, _file_len| {
Expand All @@ -147,22 +171,51 @@ pub pure fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
}
}


// FIXME #4427: Temporary until rt::rt_fail_ goes away
#[cfg(stage0)]
#[cfg(throw_unwind)]
pub pure fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
unsafe {
gc::cleanup_stack_for_failure();
rustrt::rust_upcall_fail(msg, file, line);
rustrt::rust_upcall_fail(do_throw, msg, file, line);
cast::transmute(())
}
}


pub pure fn fail_assert(msg: &str, file: &str, line: uint) -> ! {
unsafe {
let (msg, file) = (msg.to_owned(), file.to_owned());
begin_unwind(~"assertion failed: " + msg, file, line)
}
}

/** Initiate task failure */
#[cfg(return_unwind)]
pub pure fn begin_unwind(msg: ~str, file: ~str, line: uint) {
do str::as_buf(msg) |msg_buf, _msg_len| {
do str::as_buf(file) |file_buf, _file_len| {
unsafe {
let msg_buf = cast::transmute(msg_buf);
let file_buf = cast::transmute(file_buf);
begin_unwind_(msg_buf, file_buf, line as libc::size_t)
}
}
}
}


// FIXME #4427: Temporary until rt::rt_fail_ goes away
#[cfg(return_unwind)]
pub pure fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) {
unsafe {
gc::cleanup_stack_for_failure();
rustrt::rust_upcall_fail(do_throw, msg, file, line);
rusti::set_retcode_fail();
}
}

#[cfg(test)]
pub mod tests {
use cast;
Expand Down
13 changes: 12 additions & 1 deletion src/libcore/unstable/lang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub const FROZEN_BIT: uint = 0x80000000;
pub const FROZEN_BIT: uint = 0x8000000000000000;

pub mod rustrt {
use libc::{c_char, uintptr_t};
use libc::{c_char, uintptr_t, size_t};

pub extern {
#[rust_stack]
Expand All @@ -38,11 +38,22 @@ pub mod rustrt {
}
}

#[rt(fail_)]
#[lang="fail_"]
#[cfg(return_unwind)]
pub fn fail_(expr: *c_char, file: *c_char, line: size_t) {
sys::begin_unwind_(expr, file, line);
}

#[lang="fail_"]
#[cfg(stage0)]
#[cfg(throw_unwind)]
pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! {
sys::begin_unwind_(expr, file, line);
}


#[rt(fail_bounds_check)]
#[lang="fail_bounds_check"]
pub unsafe fn fail_bounds_check(file: *c_char, line: size_t,
index: size_t, len: size_t) {
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ pub fn build_configuration(sess: Session, +argv0: ~str, input: input) ->
let user_cfg = append_configuration(
user_cfg,
if sess.opts.gc { ~"gc" } else { ~"nogc" });
let user_cfg = append_configuration(
user_cfg,
if sess.return_unwind() {
~"return_unwind"
} else {
~"throw_unwind"
});
return vec::append(user_cfg, default_cfg);
}

Expand Down
14 changes: 12 additions & 2 deletions src/librustc/driver/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub const jit: uint = 1 << 19;
pub const debug_info: uint = 1 << 20;
pub const extra_debug_info: uint = 1 << 21;
pub const static: uint = 1 << 22;
pub const return_unwind: uint = 1 << 23;

pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
~[(~"verbose", ~"in general, enable more debug printouts", verbose),
Expand Down Expand Up @@ -100,7 +101,10 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
extra_debug_info),
(~"debug-info", ~"Produce debug info (experimental)", debug_info),
(~"static", ~"Use or produce static libraries or binaries " +
"(experimental)", static)
"(experimental)", static),
(~"return-unwind",
~"use return codes for unwinding (implies no-landing-pads)",
return_unwind),
]
}

Expand Down Expand Up @@ -240,6 +244,10 @@ pub impl Session_ {
}
fn verbose(@self) -> bool { self.debugging_opt(verbose) }
fn time_passes(@self) -> bool { self.debugging_opt(time_passes) }
fn no_landing_pads(@self) -> bool {
self.debugging_opt(no_landing_pads) ||
self.debugging_opt(return_unwind)
}
fn count_llvm_insns(@self) -> bool {
self.debugging_opt(count_llvm_insns)
}
Expand All @@ -265,7 +273,9 @@ pub impl Session_ {
fn no_monomorphic_collapse(@self) -> bool {
self.debugging_opt(no_monomorphic_collapse)
}

fn return_unwind(@self) -> bool {
self.debugging_opt(return_unwind)
}
fn str_of(@self, id: ast::ident) -> @~str {
self.parse_sess.interner.get(id)
}
Expand Down
52 changes: 35 additions & 17 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,16 @@ pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block {
}
let normal_bcx = sub_block(bcx, ~"normal return");
Invoke(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx));
return normal_bcx;
normal_bcx
} else if bcx.fcx.ccx.sess.return_unwind() {
debug!("calling with return-unwind check");
let v = Call(bcx, llfn, llargs);
do with_cond(bcx, Not(bcx, v)) |bcx| {
Store(bcx, C_bool(false), controlflow::get_llretcode(bcx));
cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
Unreachable(bcx);
bcx
}
} else {
unsafe {
debug!("calling %x at %x",
Expand All @@ -833,12 +842,12 @@ pub fn invoke(bcx: block, llfn: ValueRef, +llargs: ~[ValueRef]) -> block {
}
}
Call(bcx, llfn, llargs);
return bcx;
bcx
}
}

pub fn need_invoke(bcx: block) -> bool {
if (bcx.ccx().sess.opts.debugging_opts & session::no_landing_pads != 0) {
if (bcx.ccx().sess.no_landing_pads()) {
return false;
}

Expand Down Expand Up @@ -1258,8 +1267,7 @@ pub fn trans_block_cleanups_(bcx: block,
let _icx = bcx.insn_ctxt("trans_block_cleanups");
// NB: Don't short-circuit even if this block is unreachable because
// GC-based cleanup needs to the see that the roots are live.
let no_lpads =
bcx.ccx().sess.opts.debugging_opts & session::no_landing_pads != 0;
let no_lpads = bcx.ccx().sess.no_landing_pads();
if bcx.unreachable && !no_lpads { return bcx; }
let mut bcx = bcx;
for vec::rev_each(cleanups) |cu| {
Expand Down Expand Up @@ -1524,7 +1532,7 @@ pub fn alloca_maybe_zeroed(cx: block, t: TypeRef, zero: bool) -> ValueRef {
let _icx = cx.insn_ctxt("alloca");
if cx.unreachable {
unsafe {
return llvm::LLVMGetUndef(t);
return llvm::LLVMGetUndef(T_ptr(t));
}
}
let initcx = base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas);
Expand All @@ -1537,7 +1545,7 @@ pub fn arrayalloca(cx: block, t: TypeRef, v: ValueRef) -> ValueRef {
let _icx = cx.insn_ctxt("arrayalloca");
if cx.unreachable {
unsafe {
return llvm::LLVMGetUndef(t);
return llvm::LLVMGetUndef(T_ptr(t));
}
}
return ArrayAlloca(
Expand Down Expand Up @@ -1583,6 +1591,7 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
llstaticallocas: llbbs.sa,
llloadenv: None,
llreturn: llbbs.rt,
llretcode: None,
llself: None,
personality: None,
loop_ret: None,
Expand Down Expand Up @@ -1729,7 +1738,10 @@ pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) {
let _icx = fcx.insn_ctxt("finish_fn");
tie_up_header_blocks(fcx, lltop);
let ret_cx = raw_block(fcx, false, fcx.llreturn);
RetVoid(ret_cx);
match fcx.llretcode {
None => Ret(ret_cx, C_bool(true)),
Some(addr) => Ret(ret_cx, Load(ret_cx, addr))
}
}

pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
Expand Down Expand Up @@ -2225,7 +2237,19 @@ pub fn create_main_wrapper(ccx: @CrateContext,
let lloutputarg = unsafe { llvm::LLVMGetParam(llfdecl, 0 as c_uint) };
let llenvarg = unsafe { llvm::LLVMGetParam(llfdecl, 1 as c_uint) };
let mut args = ~[lloutputarg, llenvarg];
Call(bcx, main_llfn, args);

let bcx = if bcx.fcx.ccx.sess.return_unwind() {
let v = Call(bcx, main_llfn, args);
do with_cond(bcx, Not(bcx, v)) |bcx| {
Store(bcx, C_bool(false), controlflow::get_llretcode(bcx));
cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
Unreachable(bcx);
bcx
}
} else {
Call(bcx, main_llfn, args);
bcx
};

build_return(bcx);
finish_fn(fcx, lltop);
Expand Down Expand Up @@ -2460,13 +2484,7 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef {
let class_ty = ty::lookup_item_type(tcx, parent_id).ty;
// This code shouldn't be reached if the class is generic
fail_unless!(!ty::type_has_params(class_ty));
let lldty = unsafe {
T_fn(~[
T_ptr(type_of(ccx, ty::mk_nil(tcx))),
T_ptr(type_of(ccx, class_ty))
],
llvm::LLVMVoidType())
};
let lldty = type_of_dtor(ccx, class_ty);
let s = get_dtor_symbol(ccx, /*bad*/copy *pt, dt.node.id, None);

/* Make the declaration for the dtor */
Expand Down Expand Up @@ -3032,7 +3050,7 @@ pub fn trans_crate(sess: session::Session,
let task_type = T_task(targ_cfg);
let taskptr_type = T_ptr(task_type);
lib::llvm::associate_type(tn, @"taskptr", taskptr_type);
let tydesc_type = T_tydesc(targ_cfg);
let tydesc_type = T_tydesc(sess);
lib::llvm::associate_type(tn, @"tydesc", tydesc_type);
let crate_map = decl_crate_map(sess, link_meta, llmod);
let dbg_cx = if sess.opts.debuginfo {
Expand Down
12 changes: 8 additions & 4 deletions src/librustc/middle/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@ pub struct fn_ctxt_ {
// allowing most any operation to be performed on them.)
llloadenv: Option<BasicBlockRef>,
llreturn: BasicBlockRef,

// An alloca holding the 'true' value we return normally; written to
// 'false' when we're returning failure.
llretcode: Option<ValueRef>,

// The 'self' value currently in use in this function, if there
// is one.
//
Expand Down Expand Up @@ -917,15 +922,14 @@ pub fn T_generic_glue_fn(cx: @CrateContext) -> TypeRef {
return t;
}

pub fn T_tydesc(targ_cfg: @session::config) -> TypeRef {
pub fn T_tydesc(sess: session::Session) -> TypeRef {
let tydesc = T_named_struct(~"tydesc");
let tydescpp = T_ptr(T_ptr(tydesc));
let pvoid = T_ptr(T_i8());
let glue_fn_ty =
T_ptr(T_fn(~[T_ptr(T_nil()), T_ptr(T_nil()), tydescpp,
pvoid], T_void()));

let int_type = T_int(targ_cfg);
pvoid], T_bool()));
let int_type = T_int(sess.targ_cfg);
let elems =
~[int_type, int_type,
glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty,
Expand Down
Loading