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

More defailbloating #16100

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
30 changes: 28 additions & 2 deletions src/libcore/failure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//! interface for failure is:
//!
//! ```ignore
//! fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> !;
//! fn begin_unwind(fmt: &fmt::Arguments, &(&'static str, uint)) -> !;
//! ```
//!
//! This definition allows for failing with any general message, but it does not
Expand All @@ -33,6 +33,7 @@
use fmt;
use intrinsics;

#[cfg(stage0)]
#[cold] #[inline(never)] // this is the slow path, always
#[lang="fail_"]
fn fail_(expr: &'static str, file: &'static str, line: uint) -> ! {
Expand All @@ -43,6 +44,7 @@ fn fail_(expr: &'static str, file: &'static str, line: uint) -> ! {
unsafe { intrinsics::abort() }
}

#[cfg(stage0)]
#[cold]
#[lang="fail_bounds_check"]
fn fail_bounds_check(file: &'static str, line: uint,
Expand All @@ -53,7 +55,31 @@ fn fail_bounds_check(file: &'static str, line: uint,
unsafe { intrinsics::abort() }
}

#[cold]
#[cfg(not(stage0))]
#[cold] #[inline(never)] // this is the slow path, always
#[lang="fail_"]
fn fail_(expr_file_line: &(&'static str, &'static str, uint)) -> ! {
let (expr, file, line) = *expr_file_line;
let ref file_line = (file, line);
format_args!(|args| -> () {
begin_unwind(args, file_line);
}, "{}", expr);

unsafe { intrinsics::abort() }
}

#[cfg(not(stage0))]
#[cold] #[inline(never)]
#[lang="fail_bounds_check"]
fn fail_bounds_check(file_line: &(&'static str, uint),
index: uint, len: uint) -> ! {
format_args!(|args| -> () {
begin_unwind(args, file_line);
}, "index out of bounds: the len is {} but the index is {}", len, index);
unsafe { intrinsics::abort() }
}

#[cold] #[inline(never)]
pub fn begin_unwind(fmt: &fmt::Arguments, file_line: &(&'static str, uint)) -> ! {
#[allow(ctypes)]
extern {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fn const_vec(cx: &CrateContext, e: &ast::Expr,
(v, llunitty, inlineable.iter().fold(true, |a, &b| a && b))
}

fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef {
pub fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef {
unsafe {
let gv = "const".with_c_str(|name| {
llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
Expand Down
28 changes: 13 additions & 15 deletions src/librustc/middle/trans/controlflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use middle::trans::callee;
use middle::trans::cleanup::CleanupMethods;
use middle::trans::cleanup;
use middle::trans::common::*;
use middle::trans::consts;
use middle::trans::datum;
use middle::trans::debuginfo;
use middle::trans::expr;
Expand Down Expand Up @@ -472,14 +473,6 @@ pub fn trans_ret<'a>(bcx: &'a Block<'a>,
return bcx;
}

fn str_slice_arg<'a>(bcx: &'a Block<'a>, s: InternedString) -> ValueRef {
let ccx = bcx.ccx();
let s = C_str_slice(ccx, s);
let slot = alloca(bcx, val_ty(s), "__temp");
Store(bcx, s, slot);
slot
}

pub fn trans_fail<'a>(
bcx: &'a Block<'a>,
sp: Span,
Expand All @@ -488,12 +481,14 @@ pub fn trans_fail<'a>(
let ccx = bcx.ccx();
let _icx = push_ctxt("trans_fail_value");

let v_str = str_slice_arg(bcx, fail_str);
let v_str = C_str_slice(ccx, fail_str);
let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
let filename = token::intern_and_get_ident(loc.file.name.as_slice());
let v_filename = str_slice_arg(bcx, filename);
let v_line = loc.line as int;
let args = vec!(v_str, v_filename, C_int(ccx, v_line));
let filename = C_str_slice(ccx, filename);
let line = C_int(ccx, loc.line as int);
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
let expr_file_line = consts::const_addr_of(ccx, expr_file_line_const);
let args = vec!(expr_file_line);
let did = langcall(bcx, Some(sp), "", FailFnLangItem);
let bcx = callee::trans_lang_call(bcx,
did,
Expand All @@ -509,16 +504,19 @@ pub fn trans_fail_bounds_check<'a>(
index: ValueRef,
len: ValueRef)
-> &'a Block<'a> {
let ccx = bcx.ccx();
let _icx = push_ctxt("trans_fail_bounds_check");

// Extract the file/line from the span
let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
let filename = token::intern_and_get_ident(loc.file.name.as_slice());

// Invoke the lang item
let filename = str_slice_arg(bcx, filename);
let line = C_int(bcx.ccx(), loc.line as int);
let args = vec!(filename, line, index, len);
let filename = C_str_slice(ccx, filename);
let line = C_int(ccx, loc.line as int);
let file_line_const = C_struct(ccx, &[filename, line], false);
let file_line = consts::const_addr_of(ccx, file_line_const);
let args = vec!(file_line, index, len);
let did = langcall(bcx, Some(sp), "", FailBoundsCheckFnLangItem);
let bcx = callee::trans_lang_call(bcx,
did,
Expand Down
17 changes: 16 additions & 1 deletion src/librustrt/unwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,8 @@ pub fn begin_unwind_fmt(msg: &fmt::Arguments, file_line: &(&'static str, uint))
begin_unwind_inner(box String::from_utf8(v).unwrap(), file_line)
}

// FIXME: Need to change expr_fail in AstBuilder to change this to &(str, uint)
/// This is the entry point of unwinding for fail!() and assert!().
#[cfg(stage0)]
#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> ! {
// Note that this should be the only allocation performed in this code path.
Expand All @@ -432,6 +432,21 @@ pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> !
begin_unwind_inner(box msg, &(file, line))
}

/// This is the entry point of unwinding for fail!() and assert!().
#[cfg(not(stage0))]
#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, uint)) -> ! {
// Note that this should be the only allocation performed in this code path.
// Currently this means that fail!() on OOM will invoke this code path,
// but then again we're not really ready for failing on OOM anyway. If
// we do start doing this, then we should propagate this allocation to
// be performed in the parent of this task instead of the task that's
// failing.

// see below for why we do the `Any` coercion here.
begin_unwind_inner(box msg, file_line)
}

/// The core of the unwinding.
///
/// This is non-generic to avoid instantiation bloat in other crates
Expand Down
33 changes: 33 additions & 0 deletions src/libstd/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,39 @@
/// fail!("this is a {} {message}", "fancy", message = "message");
/// ```
#[macro_export]
#[cfg(not(stage0))]
macro_rules! fail(
() => ({
fail!("explicit failure")
});
($msg:expr) => ({
// static requires less code at runtime, more constant data
static FILE_LINE: (&'static str, uint) = (file!(), line!());
::std::rt::begin_unwind($msg, &FILE_LINE)
});
($fmt:expr, $($arg:tt)*) => ({
// a closure can't have return type !, so we need a full
// function to pass to format_args!, *and* we need the
// file and line numbers right here; so an inner bare fn
// is our only choice.
//
// LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
// is #[cold] and #[inline(never)] and because this is flagged as cold
// as returning !. We really do want this to be inlined, however,
// because it's just a tiny wrapper. Small wins (156K to 149K in size)
// were seen when forcing this to be inlined, and that number just goes
// up with the number of calls to fail!()
#[inline(always)]
fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
static FILE_LINE: (&'static str, uint) = (file!(), line!());
::std::rt::begin_unwind_fmt(fmt, &FILE_LINE)
}
format_args!(run_fmt, $fmt, $($arg)*)
});
)

#[macro_export]
#[cfg(stage0)]
macro_rules! fail(
() => ({
fail!("explicit failure")
Expand Down
13 changes: 8 additions & 5 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {

fn expr_fail(&self, span: Span, msg: InternedString) -> Gc<ast::Expr> {
let loc = self.codemap().lookup_char_pos(span.lo);
let expr_file = self.expr_str(span,
token::intern_and_get_ident(loc.file
.name
.as_slice()));
let expr_line = self.expr_uint(span, loc.line);
let expr_file_line_tuple = self.expr_tuple(span, vec!(expr_file, expr_line));
let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple);
self.expr_call_global(
span,
vec!(
Expand All @@ -690,11 +697,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
self.ident_of("begin_unwind")),
vec!(
self.expr_str(span, msg),
self.expr_str(span,
token::intern_and_get_ident(loc.file
.name
.as_slice())),
self.expr_uint(span, loc.line)))
expr_file_line_ptr))
}

fn expr_unreachable(&self, span: Span) -> Gc<ast::Expr> {
Expand Down