auto merge of #12616 : alexcrichton/rust/size, r=huonw
I've been playing around with code size when linking to libstd recently, and these were some findings I found that really helped code size. I started out by eliminating all I/O implementations from libnative and instead just return an unimplemented error.
In doing so, a `fn main() {}` executable was ~378K before this patch, and about 170K after the patch. These size wins are all pretty minor, but they all seemed pretty reasonable to me. With native I/O not stubbed out, this takes the size of an LTO executable from 675K to 400K.
This commit is contained in:
commit
5b4a141b6a
6 changed files with 119 additions and 114 deletions
|
|
@ -470,7 +470,7 @@ fn spawn_process_os(config: p::ProcessConfig,
|
|||
Err(e) => {
|
||||
assert!(e.kind == io::BrokenPipe ||
|
||||
e.kind == io::EndOfFile,
|
||||
"unexpected error: {:?}", e);
|
||||
"unexpected error: {}", e);
|
||||
Ok(SpawnProcessResult {
|
||||
pid: pid,
|
||||
handle: ptr::null()
|
||||
|
|
@ -744,7 +744,7 @@ fn waitpid(pid: pid_t) -> p::ProcessExit {
|
|||
|
||||
let mut status = 0 as c_int;
|
||||
match retry(|| unsafe { wait::waitpid(pid, &mut status, 0) }) {
|
||||
-1 => fail!("unknown waitpid error: {:?}", super::last_error()),
|
||||
-1 => fail!("unknown waitpid error: {}", super::last_error()),
|
||||
_ => {
|
||||
if imp::WIFEXITED(status) {
|
||||
p::ExitStatus(imp::WEXITSTATUS(status) as int)
|
||||
|
|
|
|||
|
|
@ -149,7 +149,14 @@ macro_rules! fail(
|
|||
// 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.
|
||||
#[inline]
|
||||
//
|
||||
// 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) -> ! {
|
||||
::std::rt::begin_unwind_fmt(fmt, file!(), line!())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -532,19 +532,19 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Div<T,T>+
|
|||
) -> Option<T> {
|
||||
match exponent {
|
||||
ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
|
||||
=> fail!("from_str_bytes_common: radix {:?} incompatible with \
|
||||
=> fail!("from_str_bytes_common: radix {} incompatible with \
|
||||
use of 'e' as decimal exponent", radix),
|
||||
ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
|
||||
=> fail!("from_str_bytes_common: radix {:?} incompatible with \
|
||||
=> fail!("from_str_bytes_common: radix {} incompatible with \
|
||||
use of 'p' as binary exponent", radix),
|
||||
_ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
|
||||
=> fail!("from_str_bytes_common: radix {:?} incompatible with \
|
||||
=> fail!("from_str_bytes_common: radix {} incompatible with \
|
||||
special values 'inf' and 'NaN'", radix),
|
||||
_ if (radix as int) < 2
|
||||
=> fail!("from_str_bytes_common: radix {:?} to low, \
|
||||
=> fail!("from_str_bytes_common: radix {} to low, \
|
||||
must lie in the range [2, 36]", radix),
|
||||
_ if (radix as int) > 36
|
||||
=> fail!("from_str_bytes_common: radix {:?} to high, \
|
||||
=> fail!("from_str_bytes_common: radix {} to high, \
|
||||
must lie in the range [2, 36]", radix),
|
||||
_ => ()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ fn version(crate_map: &CrateMap) -> i32 {
|
|||
|
||||
fn do_iter_crate_map<'a>(
|
||||
crate_map: &'a CrateMap<'a>,
|
||||
f: |&ModEntry|,
|
||||
f: |&'a ModEntry<'a>|,
|
||||
visited: &mut ~[*CrateMap<'a>]) {
|
||||
let raw = crate_map as *CrateMap<'a>;
|
||||
if visited.bsearch(|a| (*a as uint).cmp(&(raw as uint))).is_some() {
|
||||
|
|
@ -149,7 +149,7 @@ fn do_iter_crate_map<'a>(
|
|||
}
|
||||
|
||||
/// Iterates recursively over `crate_map` and all child crate maps
|
||||
pub fn iter_crate_map<'a>(crate_map: &'a CrateMap<'a>, f: |&ModEntry|) {
|
||||
pub fn iter_crate_map<'a>(crate_map: &'a CrateMap<'a>, f: |&'a ModEntry<'a>|) {
|
||||
let mut v = ~[];
|
||||
do_iter_crate_map(crate_map, f, &mut v);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,13 +13,14 @@ use from_str::from_str;
|
|||
use iter::Iterator;
|
||||
use libc::exit;
|
||||
use option::{Some, None, Option};
|
||||
use os;
|
||||
use rt::crate_map::{ModEntry, CrateMap, iter_crate_map, get_crate_map};
|
||||
use str::StrSlice;
|
||||
use str::{Str, StrSlice};
|
||||
use vec::{ImmutableVector, MutableTotalOrdVector, OwnedVector};
|
||||
#[cfg(test)] use cast::transmute;
|
||||
use vec_ng::Vec;
|
||||
|
||||
struct LogDirective {
|
||||
name: Option<~str>,
|
||||
struct LogDirective<'a> {
|
||||
name: Option<&'a str>,
|
||||
level: u32
|
||||
}
|
||||
|
||||
|
|
@ -58,36 +59,39 @@ fn parse_log_level(level: &str) -> Option<u32> {
|
|||
/// and return a vector with log directives.
|
||||
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in std::).
|
||||
/// Also supports string log levels of error, warn, info, and debug
|
||||
fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
|
||||
let mut dirs = ~[];
|
||||
fn parse_logging_spec<'a>(spec: &'a str) -> Vec<LogDirective<'a>> {
|
||||
let mut dirs = Vec::new();
|
||||
for s in spec.split(',') {
|
||||
let parts: ~[&str] = s.split('=').collect();
|
||||
let mut log_level;
|
||||
let mut name = Some(parts[0].to_owned());
|
||||
match parts.len() {
|
||||
1 => {
|
||||
if s.len() == 0 { continue }
|
||||
let mut parts = s.split('=');
|
||||
let log_level;
|
||||
let name;
|
||||
match (parts.next(), parts.next(), parts.next()) {
|
||||
(Some(part0), None, None) => {
|
||||
//if the single argument is a log-level string or number,
|
||||
//treat that as a global fallback
|
||||
let possible_log_level = parse_log_level(parts[0]);
|
||||
let possible_log_level = parse_log_level(part0);
|
||||
match possible_log_level {
|
||||
Some(num) => {
|
||||
name = None;
|
||||
log_level = num;
|
||||
},
|
||||
_ => {
|
||||
log_level = MAX_LOG_LEVEL
|
||||
None => {
|
||||
log_level = MAX_LOG_LEVEL;
|
||||
name = Some(part0);
|
||||
}
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
let possible_log_level = parse_log_level(parts[1]);
|
||||
(Some(part0), Some(part1), None) => {
|
||||
let possible_log_level = parse_log_level(part1);
|
||||
match possible_log_level {
|
||||
Some(num) => {
|
||||
name = Some(part0);
|
||||
log_level = num;
|
||||
},
|
||||
_ => {
|
||||
rterrln!("warning: invalid logging spec '{}', \
|
||||
ignoring it", parts[1]);
|
||||
ignoring it", part1);
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
@ -98,8 +102,7 @@ fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
|
|||
continue
|
||||
}
|
||||
}
|
||||
let dir = LogDirective {name: name, level: log_level};
|
||||
dirs.push(dir);
|
||||
dirs.push(LogDirective { name: name, level: log_level });
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
|
@ -134,27 +137,24 @@ fn update_entry(dirs: &[LogDirective], entry: &ModEntry) -> u32 {
|
|||
|
||||
/// Set log level for every entry in crate_map according to the sepecification
|
||||
/// in settings
|
||||
fn update_log_settings(crate_map: &CrateMap, settings: ~str) {
|
||||
let mut dirs = ~[];
|
||||
if settings.len() > 0 {
|
||||
if settings == ~"::help" || settings == ~"?" {
|
||||
rterrln!("\nCrate log map:\n");
|
||||
fn update_log_settings(crate_map: &CrateMap, settings: &str) {
|
||||
if settings == "::help" || settings == "?" {
|
||||
rterrln!("\nCrate log map:\n");
|
||||
|
||||
let mut entries = ~[];
|
||||
iter_crate_map(crate_map, |entry| entries.push(entry.name.to_owned()));
|
||||
entries.sort();
|
||||
let mut entries = Vec::new();
|
||||
iter_crate_map(crate_map, |entry| entries.push(entry.name));
|
||||
entries.as_mut_slice().sort();
|
||||
|
||||
for name in entries.iter() {
|
||||
rterrln!(" {}", *name);
|
||||
}
|
||||
unsafe { exit(1); }
|
||||
for name in entries.iter() {
|
||||
rterrln!(" {}", *name);
|
||||
}
|
||||
dirs = parse_logging_spec(settings);
|
||||
unsafe { exit(1); }
|
||||
}
|
||||
let dirs = parse_logging_spec(settings);
|
||||
|
||||
let mut n_matches: u32 = 0;
|
||||
iter_crate_map(crate_map, |entry| {
|
||||
let m = update_entry(dirs, entry);
|
||||
let m = update_entry(dirs.as_slice(), entry);
|
||||
n_matches += m;
|
||||
});
|
||||
|
||||
|
|
@ -169,18 +169,12 @@ fn update_log_settings(crate_map: &CrateMap, settings: ~str) {
|
|||
/// Configure logging by traversing the crate map and setting the
|
||||
/// per-module global logging flags based on the logging spec
|
||||
pub fn init() {
|
||||
use os;
|
||||
|
||||
let log_spec = os::getenv("RUST_LOG");
|
||||
match get_crate_map() {
|
||||
Some(crate_map) => {
|
||||
match log_spec {
|
||||
Some(spec) => {
|
||||
update_log_settings(crate_map, spec);
|
||||
}
|
||||
None => {
|
||||
update_log_settings(crate_map, ~"");
|
||||
}
|
||||
Some(spec) => update_log_settings(crate_map, spec.as_slice()),
|
||||
None => update_log_settings(crate_map, ""),
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
|
|
@ -197,124 +191,124 @@ pub fn init() {
|
|||
// Tests for parse_logging_spec()
|
||||
#[test]
|
||||
fn parse_logging_spec_valid() {
|
||||
let dirs = parse_logging_spec(~"crate1::mod1=1,crate1::mod2,crate2=4");
|
||||
let dirs = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
|
||||
let dirs = dirs.as_slice();
|
||||
assert_eq!(dirs.len(), 3);
|
||||
assert!(dirs[0].name == Some(~"crate1::mod1"));
|
||||
assert_eq!(dirs[0].name, Some("crate1::mod1"));
|
||||
assert_eq!(dirs[0].level, 1);
|
||||
|
||||
assert!(dirs[1].name == Some(~"crate1::mod2"));
|
||||
assert_eq!(dirs[1].name, Some("crate1::mod2"));
|
||||
assert_eq!(dirs[1].level, MAX_LOG_LEVEL);
|
||||
|
||||
assert!(dirs[2].name == Some(~"crate2"));
|
||||
assert_eq!(dirs[2].name, Some("crate2"));
|
||||
assert_eq!(dirs[2].level, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_logging_spec_invalid_crate() {
|
||||
// test parse_logging_spec with multiple = in specification
|
||||
let dirs = parse_logging_spec(~"crate1::mod1=1=2,crate2=4");
|
||||
let dirs = parse_logging_spec("crate1::mod1=1=2,crate2=4");
|
||||
let dirs = dirs.as_slice();
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert!(dirs[0].name == Some(~"crate2"));
|
||||
assert_eq!(dirs[0].name, Some("crate2"));
|
||||
assert_eq!(dirs[0].level, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_logging_spec_invalid_log_level() {
|
||||
// test parse_logging_spec with 'noNumber' as log level
|
||||
let dirs = parse_logging_spec(~"crate1::mod1=noNumber,crate2=4");
|
||||
let dirs = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
|
||||
let dirs = dirs.as_slice();
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert!(dirs[0].name == Some(~"crate2"));
|
||||
assert_eq!(dirs[0].name, Some("crate2"));
|
||||
assert_eq!(dirs[0].level, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_logging_spec_string_log_level() {
|
||||
// test parse_logging_spec with 'warn' as log level
|
||||
let dirs = parse_logging_spec(~"crate1::mod1=wrong,crate2=warn");
|
||||
let dirs = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
|
||||
let dirs = dirs.as_slice();
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert!(dirs[0].name == Some(~"crate2"));
|
||||
assert_eq!(dirs[0].name, Some("crate2"));
|
||||
assert_eq!(dirs[0].level, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_logging_spec_global() {
|
||||
// test parse_logging_spec with no crate
|
||||
let dirs = parse_logging_spec(~"warn,crate2=4");
|
||||
let dirs = parse_logging_spec("warn,crate2=4");
|
||||
let dirs = dirs.as_slice();
|
||||
assert_eq!(dirs.len(), 2);
|
||||
assert!(dirs[0].name == None);
|
||||
assert_eq!(dirs[0].name, None);
|
||||
assert_eq!(dirs[0].level, 2);
|
||||
assert!(dirs[1].name == Some(~"crate2"));
|
||||
assert_eq!(dirs[1].name, Some("crate2"));
|
||||
assert_eq!(dirs[1].level, 4);
|
||||
}
|
||||
|
||||
// Tests for update_entry
|
||||
#[test]
|
||||
fn update_entry_match_full_path() {
|
||||
let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
|
||||
LogDirective {name: Some(~"crate2"), level: 3}];
|
||||
let level = &mut 0;
|
||||
unsafe {
|
||||
let entry= &ModEntry {name:"crate1::mod1", log_level: level};
|
||||
let m = update_entry(dirs, transmute(entry));
|
||||
assert!(*entry.log_level == 2);
|
||||
assert!(m == 1);
|
||||
let dirs = [LogDirective { name: Some("crate1::mod1"), level: 2 },
|
||||
LogDirective { name: Some("crate2"), level: 3 }];
|
||||
let mut level = 0;
|
||||
{
|
||||
let entry = &ModEntry { name: "crate1::mod1", log_level: &mut level };
|
||||
assert_eq!(update_entry(dirs, entry), 1);
|
||||
}
|
||||
assert_eq!(level, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_entry_no_match() {
|
||||
let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
|
||||
LogDirective {name: Some(~"crate2"), level: 3}];
|
||||
let level = &mut 0;
|
||||
unsafe {
|
||||
let entry= &ModEntry {name: "crate3::mod1", log_level: level};
|
||||
let m = update_entry(dirs, transmute(entry));
|
||||
assert!(*entry.log_level == DEFAULT_LOG_LEVEL);
|
||||
assert!(m == 0);
|
||||
let dirs = [LogDirective { name: Some("crate1::mod1"), level: 2 },
|
||||
LogDirective { name: Some("crate2"), level: 3 }];
|
||||
let mut level = 0;
|
||||
{
|
||||
let entry = &ModEntry { name: "crate3::mod1", log_level: &mut level };
|
||||
assert_eq!(update_entry(dirs, entry), 0);
|
||||
}
|
||||
assert_eq!(level, DEFAULT_LOG_LEVEL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_entry_match_beginning() {
|
||||
let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
|
||||
LogDirective {name: Some(~"crate2"), level: 3}];
|
||||
let level = &mut 0;
|
||||
unsafe {
|
||||
let entry= &ModEntry {name: "crate2::mod1", log_level: level};
|
||||
let m = update_entry(dirs, transmute(entry));
|
||||
assert!(*entry.log_level == 3);
|
||||
assert!(m == 1);
|
||||
let dirs = [LogDirective { name: Some("crate1::mod1"), level: 2 },
|
||||
LogDirective { name: Some("crate2"), level: 3 }];
|
||||
let mut level = 0;
|
||||
{
|
||||
let entry= &ModEntry {name: "crate2::mod1", log_level: &mut level};
|
||||
assert_eq!(update_entry(dirs, entry), 1);
|
||||
}
|
||||
assert_eq!(level, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_entry_match_beginning_longest_match() {
|
||||
let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
|
||||
LogDirective {name: Some(~"crate2"), level: 3},
|
||||
LogDirective {name: Some(~"crate2::mod"), level: 4}];
|
||||
let level = &mut 0;
|
||||
unsafe {
|
||||
let entry = &ModEntry {name: "crate2::mod1", log_level: level};
|
||||
let m = update_entry(dirs, transmute(entry));
|
||||
assert!(*entry.log_level == 4);
|
||||
assert!(m == 1);
|
||||
let dirs = [LogDirective { name: Some("crate1::mod1"), level: 2 },
|
||||
LogDirective { name: Some("crate2"), level: 3 },
|
||||
LogDirective { name: Some("crate2::mod"), level: 4 }];
|
||||
let mut level = 0;
|
||||
{
|
||||
let entry = &ModEntry { name: "crate2::mod1", log_level: &mut level };
|
||||
assert_eq!(update_entry(dirs, entry), 1);
|
||||
}
|
||||
assert_eq!(level, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_entry_match_default() {
|
||||
let dirs = ~[LogDirective {name: Some(~"crate1::mod1"), level: 2 },
|
||||
LogDirective {name: None, level: 3}
|
||||
];
|
||||
let level = &mut 0;
|
||||
unsafe {
|
||||
let entry= &ModEntry {name: "crate1::mod1", log_level: level};
|
||||
let m = update_entry(dirs, transmute(entry));
|
||||
assert!(*entry.log_level == 2);
|
||||
assert!(m == 1);
|
||||
let entry= &ModEntry {name: "crate2::mod2", log_level: level};
|
||||
let m = update_entry(dirs, transmute(entry));
|
||||
assert!(*entry.log_level == 3);
|
||||
assert!(m == 1);
|
||||
let dirs = [LogDirective { name: Some("crate1::mod1"), level: 2 },
|
||||
LogDirective { name: None, level: 3 }];
|
||||
let mut level = 0;
|
||||
{
|
||||
let entry = &ModEntry { name: "crate1::mod1", log_level: &mut level };
|
||||
assert_eq!(update_entry(dirs, entry), 1);
|
||||
}
|
||||
assert_eq!(level, 2);
|
||||
{
|
||||
let entry = &ModEntry { name: "crate2::mod2", log_level: &mut level };
|
||||
assert_eq!(update_entry(dirs, entry), 1);
|
||||
}
|
||||
assert_eq!(level, 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ impl<T: Send> UnsafeArc<T> {
|
|||
#[inline]
|
||||
pub fn get(&self) -> *mut T {
|
||||
unsafe {
|
||||
assert!((*self.data).count.load(Relaxed) > 0);
|
||||
// FIXME(#12049): this needs some sort of debug assertion
|
||||
if cfg!(test) { assert!((*self.data).count.load(Relaxed) > 0); }
|
||||
return &mut (*self.data).data as *mut T;
|
||||
}
|
||||
}
|
||||
|
|
@ -90,7 +91,8 @@ impl<T: Send> UnsafeArc<T> {
|
|||
#[inline]
|
||||
pub fn get_immut(&self) -> *T {
|
||||
unsafe {
|
||||
assert!((*self.data).count.load(Relaxed) > 0);
|
||||
// FIXME(#12049): this needs some sort of debug assertion
|
||||
if cfg!(test) { assert!((*self.data).count.load(Relaxed) > 0); }
|
||||
return &(*self.data).data as *T;
|
||||
}
|
||||
}
|
||||
|
|
@ -109,7 +111,8 @@ impl<T: Send> Clone for UnsafeArc<T> {
|
|||
unsafe {
|
||||
// This barrier might be unnecessary, but I'm not sure...
|
||||
let old_count = (*self.data).count.fetch_add(1, Acquire);
|
||||
assert!(old_count >= 1);
|
||||
// FIXME(#12049): this needs some sort of debug assertion
|
||||
if cfg!(test) { assert!(old_count >= 1); }
|
||||
return UnsafeArc { data: self.data };
|
||||
}
|
||||
}
|
||||
|
|
@ -127,7 +130,8 @@ impl<T> Drop for UnsafeArc<T>{
|
|||
// Must be acquire+release, not just release, to make sure this
|
||||
// doesn't get reordered to after the unwrapper pointer load.
|
||||
let old_count = (*self.data).count.fetch_sub(1, SeqCst);
|
||||
assert!(old_count >= 1);
|
||||
// FIXME(#12049): this needs some sort of debug assertion
|
||||
if cfg!(test) { assert!(old_count >= 1); }
|
||||
if old_count == 1 {
|
||||
let _: ~ArcData<T> = cast::transmute(self.data);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue