Auto merge of #27400 - alexcrichton:less-jemalloc, r=brson

This commit is an implementation of [RFC 1183][rfc] which allows swapping out
the default allocator on nightly Rust. No new stable surface area should be
added as a part of this commit.

[rfc]: https://github.com/rust-lang/rfcs/pull/1183

Two new attributes have been added to the compiler:

* `#![needs_allocator]` - this is used by liballoc (and likely only liballoc) to
  indicate that it requires an allocator crate to be in scope.
* `#![allocator]` - this is a indicator that the crate is an allocator which can
  satisfy the `needs_allocator` attribute above.

The ABI of the allocator crate is defined to be a set of symbols that implement
the standard Rust allocation/deallocation functions. The symbols are not
currently checked for exhaustiveness or typechecked. There are also a number of
restrictions on these crates:

* An allocator crate cannot transitively depend on a crate that is flagged as
  needing an allocator (e.g. allocator crates can't depend on liballoc).
* There can only be one explicitly linked allocator in a final image.
* If no allocator is explicitly requested one will be injected on behalf of the
  compiler. Binaries and Rust dylibs will use jemalloc by default where
  available and staticlibs/other dylibs will use the system allocator by
  default.

Two allocators are provided by the distribution by default, `alloc_system` and
`alloc_jemalloc` which operate as advertised.

Closes #27389
This commit is contained in:
bors 2015-08-14 22:52:11 +00:00
commit ab450ef22b
55 changed files with 1287 additions and 647 deletions

View file

@ -52,23 +52,23 @@
TARGET_CRATES := libc std flate arena term \
serialize getopts collections test rand \
log graphviz core rbml alloc \
rustc_unicode rustc_bitflags
rustc_unicode rustc_bitflags \
alloc_system
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
rustc_data_structures
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustdoc rustc rustbook error-index-generator
DEPS_core :=
DEPS_libc := core
DEPS_rustc_unicode := core
DEPS_alloc := core libc native:jemalloc
DEPS_alloc := core libc alloc_system
DEPS_std := core libc rand alloc collections rustc_unicode \
native:rust_builtin native:backtrace \
rustc_bitflags
alloc_system
DEPS_graphviz := std
DEPS_syntax := std term serialize log fmt_macros arena libc
DEPS_syntax := std term serialize log fmt_macros arena libc rustc_bitflags
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy rustc_lint
@ -82,7 +82,7 @@ DEPS_rustc_privacy := rustc log syntax
DEPS_rustc_lint := rustc log syntax
DEPS_rustc := syntax flate arena serialize getopts rbml \
log graphviz rustc_llvm rustc_back rustc_data_structures
DEPS_rustc_llvm := native:rustllvm libc std
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_back := std syntax rustc_llvm flate log libc
DEPS_rustc_data_structures := std log serialize
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
@ -102,6 +102,7 @@ DEPS_test := std getopts serialize rbml term native:rust_test_helpers
DEPS_rand := core
DEPS_log := std
DEPS_fmt_macros = std
DEPS_alloc_system := core libc
TOOL_DEPS_compiletest := test getopts
TOOL_DEPS_rustdoc := rustdoc
@ -121,14 +122,26 @@ ONLY_RLIB_rand := 1
ONLY_RLIB_collections := 1
ONLY_RLIB_rustc_unicode := 1
ONLY_RLIB_rustc_bitflags := 1
ONLY_RLIB_alloc_system := 1
# Documented-by-default crates
DOC_CRATES := std alloc collections core libc rustc_unicode
ifeq ($(CFG_DISABLE_JEMALLOC),)
TARGET_CRATES += alloc_jemalloc
DEPS_std += alloc_jemalloc
DEPS_alloc_jemalloc := core libc native:jemalloc
ONLY_RLIB_alloc_jemalloc := 1
else
RUSTFLAGS_rustc_back := --cfg disable_jemalloc
endif
################################################################################
# You should not need to edit below this line
################################################################################
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
# This macro creates some simple definitions for each crate being built, just
# some munging of all of the parameters above.
#

View file

@ -184,8 +184,6 @@ $$(JEMALLOC_LOCAL_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
EXTRA_CFLAGS="-g1 -ffunction-sections -fdata-sections"
$$(Q)$$(MAKE) -C "$$(JEMALLOC_BUILD_DIR_$(1))" build_lib_static
ifeq ($$(CFG_DISABLE_JEMALLOC),)
RUSTFLAGS_alloc := --cfg jemalloc
ifeq ($(1),$$(CFG_BUILD))
ifneq ($$(CFG_JEMALLOC_ROOT),)
$$(JEMALLOC_LIB_$(1)): $$(CFG_JEMALLOC_ROOT)/libjemalloc_pic.a
@ -199,10 +197,6 @@ else
$$(JEMALLOC_LIB_$(1)): $$(JEMALLOC_LOCAL_$(1))
$$(Q)cp $$< $$@
endif
else
$$(JEMALLOC_LIB_$(1)): $$(MKFILE_DEPS)
$$(Q)touch $$@
endif
################################################################################
# compiler-rt

View file

@ -22,7 +22,8 @@ $(eval $(call RUST_CRATE,coretest))
DEPS_collectionstest :=
$(eval $(call RUST_CRATE,collectionstest))
TEST_TARGET_CRATES = $(filter-out core rustc_unicode,$(TARGET_CRATES)) \
TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system \
alloc_jemalloc,$(TARGET_CRATES)) \
collectionstest coretest
TEST_DOC_CRATES = $(DOC_CRATES)
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \

View file

@ -16,6 +16,18 @@
use core::{isize, usize};
#[allow(improper_ctypes)]
extern {
#[allocator]
fn __rust_allocate(size: usize, align: usize) -> *mut u8;
fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> *mut u8;
fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> usize;
fn __rust_usable_size(size: usize, align: usize) -> usize;
}
#[inline(always)]
fn check_size_and_alignment(size: usize, align: usize) {
debug_assert!(size != 0);
@ -35,7 +47,7 @@ fn check_size_and_alignment(size: usize, align: usize) {
#[inline]
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
check_size_and_alignment(size, align);
imp::allocate(size, align)
__rust_allocate(size, align)
}
/// Resize the allocation referenced by `ptr` to `size` bytes.
@ -55,7 +67,7 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
check_size_and_alignment(size, align);
imp::reallocate(ptr, old_size, size, align)
__rust_reallocate(ptr, old_size, size, align)
}
/// Resize the allocation referenced by `ptr` to `size` bytes.
@ -74,7 +86,7 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usiz
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> usize {
check_size_and_alignment(size, align);
imp::reallocate_inplace(ptr, old_size, size, align)
__rust_reallocate_inplace(ptr, old_size, size, align)
}
/// Deallocates the memory referenced by `ptr`.
@ -86,28 +98,20 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
/// any value in range_inclusive(requested_size, usable_size).
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) {
imp::deallocate(ptr, old_size, align)
__rust_deallocate(ptr, old_size, align)
}
/// Returns the usable size of an allocation created with the specified the
/// `size` and `align`.
#[inline]
pub fn usable_size(size: usize, align: usize) -> usize {
imp::usable_size(size, align)
}
/// Prints implementation-defined allocator statistics.
///
/// These statistics may be inconsistent if other threads use the allocator
/// during the call.
pub fn stats_print() {
imp::stats_print();
unsafe { __rust_usable_size(size, align) }
}
/// An arbitrary non-null address to represent zero-size allocations.
///
/// This preserves the non-null invariant for types like `Box<T>`. The address may overlap with
/// non-zero-size memory allocations.
/// This preserves the non-null invariant for types like `Box<T>`. The address
/// may overlap with non-zero-size memory allocations.
pub const EMPTY: *mut () = 0x1 as *mut ();
/// The allocator for unique pointers.
@ -131,362 +135,6 @@ unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) {
deallocate(ptr, old_size, align);
}
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(not(feature = "external_funcs"),
not(feature = "external_crate"),
any(target_arch = "arm",
target_arch = "mips",
target_arch = "mipsel",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(not(feature = "external_funcs"),
not(feature = "external_crate"),
any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;
#[cfg(feature = "external_funcs")]
mod imp {
#[allow(improper_ctypes)]
extern {
fn rust_allocate(size: usize, align: usize) -> *mut u8;
fn rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
fn rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8;
fn rust_reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> usize;
fn rust_usable_size(size: usize, align: usize) -> usize;
fn rust_stats_print();
}
#[inline]
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
rust_allocate(size, align)
}
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) {
rust_deallocate(ptr, old_size, align)
}
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
rust_reallocate(ptr, old_size, size, align)
}
#[inline]
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> usize {
rust_reallocate_inplace(ptr, old_size, size, align)
}
#[inline]
pub fn usable_size(size: usize, align: usize) -> usize {
unsafe { rust_usable_size(size, align) }
}
#[inline]
pub fn stats_print() {
unsafe { rust_stats_print() }
}
}
#[cfg(feature = "external_crate")]
mod imp {
extern crate external;
pub use self::external::{allocate, deallocate, reallocate_inplace, reallocate};
pub use self::external::{usable_size, stats_print};
}
#[cfg(all(not(feature = "external_funcs"),
not(feature = "external_crate"),
jemalloc))]
mod imp {
use core::option::Option;
use core::option::Option::None;
use core::ptr::{null_mut, null};
use libc::{c_char, c_int, c_void, size_t};
use super::MIN_ALIGN;
#[link(name = "jemalloc", kind = "static")]
#[cfg(not(test))]
extern {}
extern {
#[allocator]
fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
fn je_nallocx(size: size_t, flags: c_int) -> size_t;
fn je_malloc_stats_print(write_cb: Option<extern "C" fn(cbopaque: *mut c_void,
*const c_char)>,
cbopaque: *mut c_void,
opts: *const c_char);
}
// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
#[cfg(all(not(windows),
not(target_os = "android"),
not(target_env = "musl")))]
#[link(name = "pthread")]
extern {}
// MALLOCX_ALIGN(a) macro
#[inline(always)]
fn mallocx_align(a: usize) -> c_int { a.trailing_zeros() as c_int }
#[inline(always)]
fn align_to_flags(align: usize) -> c_int {
if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
}
#[inline]
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
je_mallocx(size as size_t, flags) as *mut u8
}
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8
}
#[inline]
pub unsafe fn reallocate_inplace(ptr: *mut u8, _old_size: usize, size: usize,
align: usize) -> usize {
let flags = align_to_flags(align);
je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize
}
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
je_sdallocx(ptr as *mut c_void, old_size as size_t, flags)
}
#[inline]
pub fn usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { je_nallocx(size as size_t, flags) as usize }
}
pub fn stats_print() {
unsafe {
je_malloc_stats_print(None, null_mut(), null())
}
}
}
#[cfg(all(not(feature = "external_funcs"),
not(feature = "external_crate"),
not(jemalloc),
unix))]
mod imp {
use core::cmp;
use core::ptr;
use libc;
use super::MIN_ALIGN;
extern {
fn posix_memalign(memptr: *mut *mut libc::c_void,
align: libc::size_t,
size: libc::size_t) -> libc::c_int;
}
#[inline]
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
libc::malloc(size as libc::size_t) as *mut u8
} else {
let mut out = ptr::null_mut();
let ret = posix_memalign(&mut out,
align as libc::size_t,
size as libc::size_t);
if ret != 0 {
ptr::null_mut()
} else {
out as *mut u8
}
}
}
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
} else {
let new_ptr = allocate(size, align);
ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
deallocate(ptr, old_size, align);
new_ptr
}
}
#[inline]
pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize,
_align: usize) -> usize {
old_size
}
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
libc::free(ptr as *mut libc::c_void)
}
#[inline]
pub fn usable_size(size: usize, _align: usize) -> usize {
size
}
pub fn stats_print() {}
}
#[cfg(all(not(feature = "external_funcs"),
not(feature = "external_crate"),
not(jemalloc),
windows))]
mod imp {
use core::mem::size_of;
use libc::{BOOL, DWORD, HANDLE, LPVOID, SIZE_T, INVALID_HANDLE_VALUE};
use libc::{WriteFile};
use super::MIN_ALIGN;
extern "system" {
fn GetProcessHeap() -> HANDLE;
fn GetStdHandle(nStdHandle: DWORD) -> HANDLE;
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) -> BOOL;
}
#[repr(C)] #[allow(non_snake_case)]
struct HEAP_SUMMARY {
cb: DWORD,
cbAllocated: SIZE_T,
cbCommitted: SIZE_T,
cbReserved: SIZE_T,
cbMaxReserve: SIZE_T,
}
#[allow(non_camel_case_types)]
type LPHEAP_SUMMARY = *mut HEAP_SUMMARY;
#[repr(C)]
struct Header(*mut u8);
const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;
const STD_OUTPUT_HANDLE: DWORD = -11i32 as u32;
#[inline]
unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
&mut *(ptr as *mut Header).offset(-1)
}
#[inline]
unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
*get_header(aligned) = Header(ptr);
aligned
}
#[inline]
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
} else {
let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
if ptr.is_null() { return ptr }
align_ptr(ptr, align)
}
}
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
} else {
let header = get_header(ptr);
let new = HeapReAlloc(GetProcessHeap(), 0, header.0 as LPVOID,
(size + align) as SIZE_T) as *mut u8;
if new.is_null() { return new }
align_ptr(new, align)
}
}
#[inline]
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> usize {
if align <= MIN_ALIGN {
let new = HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, ptr as LPVOID,
size as SIZE_T) as *mut u8;
if new.is_null() { old_size } else { size }
} else {
old_size
}
}
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
if align <= MIN_ALIGN {
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
debug_assert!(err != 0);
} else {
let header = get_header(ptr);
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
debug_assert!(err != 0);
}
}
#[inline]
pub fn usable_size(size: usize, _align: usize) -> usize {
size
}
pub fn stats_print() {
use core::fmt::{Error, Result, Write};
use core::ptr::null_mut;
use core::raw::Repr;
use core::result::Result::{Ok, Err};
struct Console(HANDLE);
impl Write for Console {
fn write_str(&mut self, s: &str) -> Result {
let repr = s.repr();
let mut written = 0;
let err = unsafe { WriteFile(self.0, repr.data as LPVOID, repr.len as DWORD,
&mut written, null_mut()) };
if written as usize != repr.len { return Err(Error) }
if err == 0 { return Err(Error) }
Ok(())
}
}
let mut hs = HEAP_SUMMARY {
cb: size_of::<HEAP_SUMMARY>() as DWORD,
cbAllocated: 0,
cbCommitted: 0,
cbReserved: 0,
cbMaxReserve: 0,
};
let err = unsafe { HeapSummary(GetProcessHeap(), 0, &mut hs) };
assert!(err != 0);
let handle = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };
if handle.is_null() || handle == INVALID_HANDLE_VALUE { panic!("Failed to open stdout") }
let mut out = Console(handle);
writeln!(&mut out, "Allocated: {}", hs.cbAllocated).unwrap();
writeln!(&mut out, "Committed: {}", hs.cbCommitted).unwrap();
writeln!(&mut out, "Reserved: {}", hs.cbReserved).unwrap();
writeln!(&mut out, "MaxReserve: {}", hs.cbMaxReserve).unwrap();
}
#[test]
fn alignment_header_size() {
assert!(size_of::<Header>() <= MIN_ALIGN);
}
}
#[cfg(test)]
mod tests {
extern crate test;

View file

@ -61,6 +61,7 @@
#![crate_name = "alloc"]
#![crate_type = "rlib"]
#![staged_api]
#![allow(unused_attributes)]
#![unstable(feature = "alloc",
reason = "this library is unlikely to be stabilized in its current \
form or name")]
@ -69,6 +70,7 @@
html_root_url = "https://doc.rust-lang.org/nightly/",
test(no_crate_inject))]
#![no_std]
#![cfg_attr(not(stage0), needs_allocator)]
#![feature(allocator)]
#![feature(box_syntax)]
@ -92,13 +94,13 @@
#![feature(unsize)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
#![cfg_attr(stage0, feature(alloc_system))]
#![cfg_attr(not(stage0), feature(needs_allocator))]
#![cfg_attr(test, feature(test, rustc_private, box_raw))]
#![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")),
feature(libc))]
#[cfg(all(not(feature = "external_funcs"), not(feature = "external_crate")))]
extern crate libc;
#[cfg(stage0)]
extern crate alloc_system;
// Allow testing this library

View file

@ -0,0 +1,96 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "alloc_jemalloc"]
#![crate_type = "rlib"]
#![staged_api]
#![no_std]
#![cfg_attr(not(stage0), allocator)]
#![unstable(feature = "alloc_jemalloc",
reason = "this library is unlikely to be stabilized in its current \
form or name")]
#![feature(allocator)]
#![feature(libc)]
#![feature(no_std)]
#![feature(staged_api)]
extern crate libc;
use libc::{c_int, c_void, size_t};
#[link(name = "jemalloc", kind = "static")]
extern {
fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
flags: c_int) -> size_t;
fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
fn je_nallocx(size: size_t, flags: c_int) -> size_t;
}
// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
#[cfg(all(not(windows),
not(target_os = "android"),
not(target_env = "musl")))]
#[link(name = "pthread")]
extern {}
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
target_arch = "mips",
target_arch = "mipsel",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;
// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int { a.trailing_zeros() as c_int }
fn align_to_flags(align: usize) -> c_int {
if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
}
#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { je_mallocx(size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern fn __rust_reallocate_inplace(ptr: *mut u8, _old_size: usize,
size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}
#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
unsafe { je_sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}
#[no_mangle]
pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { je_nallocx(size as size_t, flags) as usize }
}

212
src/liballoc_system/lib.rs Normal file
View file

@ -0,0 +1,212 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "alloc_system"]
#![crate_type = "rlib"]
#![staged_api]
#![no_std]
#![cfg_attr(not(stage0), allocator)]
#![unstable(feature = "alloc_system",
reason = "this library is unlikely to be stabilized in its current \
form or name")]
#![feature(allocator)]
#![feature(libc)]
#![feature(no_std)]
#![feature(staged_api)]
extern crate libc;
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
target_arch = "mips",
target_arch = "mipsel",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;
#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
unsafe { imp::allocate(size, align) }
}
#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
unsafe { imp::deallocate(ptr, old_size, align) }
}
#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> *mut u8 {
unsafe { imp::reallocate(ptr, old_size, size, align) }
}
#[no_mangle]
pub extern fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize,
size: usize, align: usize) -> usize {
unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
}
#[no_mangle]
pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
imp::usable_size(size, align)
}
#[cfg(unix)]
mod imp {
use core::cmp;
use core::ptr;
use libc;
use MIN_ALIGN;
extern {
// Apparently android doesn't have posix_memalign
#[cfg(target_os = "android")]
fn memalign(align: libc::size_t, size: libc::size_t) -> *mut libc::c_void;
#[cfg(not(target_os = "android"))]
fn posix_memalign(memptr: *mut *mut libc::c_void,
align: libc::size_t,
size: libc::size_t) -> libc::c_int;
}
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
libc::malloc(size as libc::size_t) as *mut u8
} else {
#[cfg(target_os = "android")]
unsafe fn more_aligned_malloc(size: usize, align: usize) -> *mut u8 {
memalign(align as libc::size_t, size as libc::size_t) as *mut u8
}
#[cfg(not(target_os = "android"))]
unsafe fn more_aligned_malloc(size: usize, align: usize) -> *mut u8 {
let mut out = ptr::null_mut();
let ret = posix_memalign(&mut out,
align as libc::size_t,
size as libc::size_t);
if ret != 0 {
ptr::null_mut()
} else {
out as *mut u8
}
}
more_aligned_malloc(size, align)
}
}
pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
} else {
let new_ptr = allocate(size, align);
ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
deallocate(ptr, old_size, align);
new_ptr
}
}
pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize,
_align: usize) -> usize {
old_size
}
pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
libc::free(ptr as *mut libc::c_void)
}
pub fn usable_size(size: usize, _align: usize) -> usize {
size
}
}
#[cfg(windows)]
mod imp {
use libc::{BOOL, DWORD, HANDLE, LPVOID, SIZE_T};
use MIN_ALIGN;
extern "system" {
fn GetProcessHeap() -> HANDLE;
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID,
dwBytes: SIZE_T) -> LPVOID;
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
}
#[repr(C)]
struct Header(*mut u8);
const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;
unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
&mut *(ptr as *mut Header).offset(-1)
}
unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
*get_header(aligned) = Header(ptr);
aligned
}
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
} else {
let ptr = HeapAlloc(GetProcessHeap(), 0,
(size + align) as SIZE_T) as *mut u8;
if ptr.is_null() { return ptr }
align_ptr(ptr, align)
}
}
pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize,
align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
} else {
let header = get_header(ptr);
let new = HeapReAlloc(GetProcessHeap(), 0, header.0 as LPVOID,
(size + align) as SIZE_T) as *mut u8;
if new.is_null() { return new }
align_ptr(new, align)
}
}
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> usize {
if align <= MIN_ALIGN {
let new = HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY,
ptr as LPVOID, size as SIZE_T) as *mut u8;
if new.is_null() { old_size } else { size }
} else {
old_size
}
}
pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
if align <= MIN_ALIGN {
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
debug_assert!(err != 0);
} else {
let header = get_header(ptr);
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
debug_assert!(err != 0);
}
}
pub fn usable_size(size: usize, _align: usize) -> usize {
size
}
}

View file

@ -78,12 +78,13 @@ pub const tag_crate_crate_name: usize = 0x104; // top-level only
pub const tag_crate_dep_crate_name: usize = 0x36;
pub const tag_crate_dep_hash: usize = 0x37;
pub const tag_crate_dep_explicitly_linked: usize = 0x38; // top-level only
pub const tag_mod_impl: usize = 0x38;
pub const tag_mod_impl: usize = 0x39;
pub const tag_item_trait_item: usize = 0x39;
pub const tag_item_trait_item: usize = 0x3a;
pub const tag_item_trait_ref: usize = 0x3a;
pub const tag_item_trait_ref: usize = 0x3b;
// discriminator value for variants
pub const tag_disr_val: usize = 0x3c;

View file

@ -22,7 +22,7 @@ use metadata::loader;
use metadata::loader::CratePaths;
use util::nodemap::FnvHashMap;
use std::cell::RefCell;
use std::cell::{RefCell, Cell};
use std::path::PathBuf;
use std::rc::Rc;
use std::fs;
@ -59,15 +59,16 @@ impl<'a, 'b, 'v> visit::Visitor<'v> for LocalCrateReader<'a, 'b> {
}
fn dump_crates(cstore: &CStore) {
debug!("resolved crates:");
info!("resolved crates:");
cstore.iter_crate_data_origins(|_, data, opt_source| {
debug!(" name: {}", data.name());
debug!(" cnum: {}", data.cnum);
debug!(" hash: {}", data.hash());
info!(" name: {}", data.name());
info!(" cnum: {}", data.cnum);
info!(" hash: {}", data.hash());
info!(" reqd: {}", data.explicitly_linked.get());
opt_source.map(|cs| {
let CrateSource { dylib, rlib, cnum: _ } = cs;
dylib.map(|dl| debug!(" dylib: {}", dl.0.display()));
rlib.map(|rl| debug!(" rlib: {}", rl.0.display()));
dylib.map(|dl| info!(" dylib: {}", dl.0.display()));
rlib.map(|rl| info!(" rlib: {}", rl.0.display()));
});
})
}
@ -241,7 +242,8 @@ impl<'a> CrateReader<'a> {
ident: &str,
name: &str,
span: Span,
lib: loader::Library)
lib: loader::Library,
explicitly_linked: bool)
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
// Claim this crate number and cache it
@ -266,15 +268,16 @@ impl<'a> CrateReader<'a> {
let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span);
let staged_api = self.is_staged_api(metadata.as_slice());
let cmeta = Rc::new( cstore::crate_metadata {
let cmeta = Rc::new(cstore::crate_metadata {
name: name.to_string(),
local_path: RefCell::new(SmallVector::zero()),
data: metadata,
cnum_map: cnum_map,
cnum_map: RefCell::new(cnum_map),
cnum: cnum,
codemap_import_info: RefCell::new(vec![]),
span: span,
staged_api: staged_api
staged_api: staged_api,
explicitly_linked: Cell::new(explicitly_linked),
});
let source = cstore::CrateSource {
@ -305,7 +308,8 @@ impl<'a> CrateReader<'a> {
name: &str,
hash: Option<&Svh>,
span: Span,
kind: PathKind)
kind: PathKind,
explicitly_linked: bool)
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
match self.existing_match(name, hash, kind) {
@ -326,11 +330,16 @@ impl<'a> CrateReader<'a> {
should_match_name: true,
};
let library = load_ctxt.load_library_crate();
self.register_crate(root, ident, name, span, library)
self.register_crate(root, ident, name, span, library,
explicitly_linked)
}
Some(cnum) => {
let data = self.sess.cstore.get_crate_data(cnum);
if explicitly_linked && !data.explicitly_linked.get() {
data.explicitly_linked.set(explicitly_linked);
}
(cnum, data, self.sess.cstore.get_used_crate_source(cnum).unwrap())
}
Some(cnum) => (cnum,
self.sess.cstore.get_crate_data(cnum),
self.sess.cstore.get_used_crate_source(cnum).unwrap())
}
}
@ -349,7 +358,8 @@ impl<'a> CrateReader<'a> {
&dep.name,
Some(&dep.hash),
span,
PathKind::Dependency);
PathKind::Dependency,
dep.explicitly_linked);
(dep.cnum, local_cnum)
}).collect()
}
@ -399,7 +409,8 @@ impl<'a> CrateReader<'a> {
let metadata = if register {
// Register crate now to avoid double-reading metadata
let (_, cmd, _) = self.register_crate(&None, &info.ident,
&info.name, span, library);
&info.name, span, library,
true);
PMDSource::Registered(cmd)
} else {
// Not registering the crate; just hold on to the metadata
@ -507,6 +518,124 @@ impl<'a> CrateReader<'a> {
}
}
}
fn inject_allocator_crate(&mut self) {
// Make sure that we actually need an allocator, if none of our
// dependencies need one then we definitely don't!
//
// Also, if one of our dependencies has an explicit allocator, then we
// also bail out as we don't need to implicitly inject one.
let mut needs_allocator = false;
let mut found_required_allocator = false;
self.sess.cstore.iter_crate_data(|cnum, data| {
needs_allocator = needs_allocator || data.needs_allocator();
if data.is_allocator() {
debug!("{} required by rlib and is an allocator", data.name());
self.inject_allocator_dependency(cnum);
found_required_allocator = found_required_allocator ||
data.explicitly_linked.get();
}
});
if !needs_allocator || found_required_allocator { return }
// At this point we've determined that we need an allocator and no
// previous allocator has been activated. We look through our outputs of
// crate types to see what kind of allocator types we may need.
//
// The main special output type here is that rlibs do **not** need an
// allocator linked in (they're just object files), only final products
// (exes, dylibs, staticlibs) need allocators.
let mut need_lib_alloc = false;
let mut need_exe_alloc = false;
for ct in self.sess.crate_types.borrow().iter() {
match *ct {
config::CrateTypeExecutable => need_exe_alloc = true,
config::CrateTypeDylib |
config::CrateTypeStaticlib => need_lib_alloc = true,
config::CrateTypeRlib => {}
}
}
if !need_lib_alloc && !need_exe_alloc { return }
// The default allocator crate comes from the custom target spec, and we
// choose between the standard library allocator or exe allocator. This
// distinction exists because the default allocator for binaries (where
// the world is Rust) is different than library (where the world is
// likely *not* Rust).
//
// If a library is being produced, but we're also flagged with `-C
// prefer-dynamic`, then we interpret this as a *Rust* dynamic library
// is being produced so we use the exe allocator instead.
//
// What this boils down to is:
//
// * Binaries use jemalloc
// * Staticlibs and Rust dylibs use system malloc
// * Rust dylibs used as dependencies to rust use jemalloc
let name = if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
&self.sess.target.target.options.lib_allocation_crate
} else {
&self.sess.target.target.options.exe_allocation_crate
};
let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
codemap::DUMMY_SP,
PathKind::Crate, false);
// To ensure that the `-Z allocation-crate=foo` option isn't abused, and
// to ensure that the allocator is indeed an allocator, we verify that
// the crate loaded here is indeed tagged #![allocator].
if !data.is_allocator() {
self.sess.err(&format!("the allocator crate `{}` is not tagged \
with #![allocator]", data.name()));
}
self.sess.injected_allocator.set(Some(cnum));
self.inject_allocator_dependency(cnum);
}
fn inject_allocator_dependency(&self, allocator: ast::CrateNum) {
// Before we inject any dependencies, make sure we don't inject a
// circular dependency by validating that this allocator crate doesn't
// transitively depend on any `#![needs_allocator]` crates.
validate(self, allocator, allocator);
// All crates tagged with `needs_allocator` do not explicitly depend on
// the allocator selected for this compile, but in order for this
// compilation to be successfully linked we need to inject a dependency
// (to order the crates on the command line correctly).
//
// Here we inject a dependency from all crates with #![needs_allocator]
// to the crate tagged with #![allocator] for this compilation unit.
self.sess.cstore.iter_crate_data(|cnum, data| {
if !data.needs_allocator() {
return
}
info!("injecting a dep from {} to {}", cnum, allocator);
let mut cnum_map = data.cnum_map.borrow_mut();
let remote_cnum = cnum_map.len() + 1;
let prev = cnum_map.insert(remote_cnum as ast::CrateNum, allocator);
assert!(prev.is_none());
});
fn validate(me: &CrateReader, krate: ast::CrateNum,
allocator: ast::CrateNum) {
let data = me.sess.cstore.get_crate_data(krate);
if data.needs_allocator() {
let krate_name = data.name();
let data = me.sess.cstore.get_crate_data(allocator);
let alloc_name = data.name();
me.sess.err(&format!("the allocator crate `{}` cannot depend \
on a crate that needs an allocator, but \
it depends on `{}`", alloc_name,
krate_name));
}
for (_, &dep) in data.cnum_map.borrow().iter() {
validate(me, dep, allocator);
}
}
}
}
impl<'a, 'b> LocalCrateReader<'a, 'b> {
@ -524,8 +653,9 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> {
pub fn read_crates(&mut self, krate: &ast::Crate) {
self.process_crate(krate);
visit::walk_crate(self, krate);
self.creader.inject_allocator_crate();
if log_enabled!(log::DEBUG) {
if log_enabled!(log::INFO) {
dump_crates(&self.sess.cstore);
}
@ -558,7 +688,8 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> {
&info.name,
None,
i.span,
PathKind::Crate);
PathKind::Crate,
true);
self.ast_map.with_path(i.id, |path| {
cmeta.update_local_path(path)
});

View file

@ -22,11 +22,12 @@ use metadata::{creader, decoder, loader};
use session::search_paths::PathKind;
use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use std::cell::{RefCell, Ref};
use std::cell::{RefCell, Ref, Cell};
use std::rc::Rc;
use std::path::PathBuf;
use flate::Bytes;
use syntax::ast;
use syntax::attr;
use syntax::codemap;
use syntax::parse::token;
use syntax::parse::token::IdentInterner;
@ -59,11 +60,17 @@ pub struct crate_metadata {
pub name: String,
pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
pub data: MetadataBlob,
pub cnum_map: cnum_map,
pub cnum_map: RefCell<cnum_map>,
pub cnum: ast::CrateNum,
pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
pub span: codemap::Span,
pub staged_api: bool
pub staged_api: bool,
/// Flag if this crate is required by an rlib version of this crate, or in
/// other words whether it was explicitly linked to. An example of a crate
/// where this is false is when an allocator crate is injected into the
/// dependency list, and therefore isn't actually needed to link an rlib.
pub explicitly_linked: Cell<bool>,
}
#[derive(Copy, Debug, PartialEq, Clone)]
@ -132,10 +139,10 @@ impl CStore {
}
pub fn iter_crate_data<I>(&self, mut i: I) where
I: FnMut(ast::CrateNum, &crate_metadata),
I: FnMut(ast::CrateNum, &Rc<crate_metadata>),
{
for (&k, v) in self.metas.borrow().iter() {
i(k, &**v);
i(k, v);
}
}
@ -188,7 +195,7 @@ impl CStore {
ordering: &mut Vec<ast::CrateNum>) {
if ordering.contains(&cnum) { return }
let meta = cstore.get_crate_data(cnum);
for (_, &dep) in &meta.cnum_map {
for (_, &dep) in meta.cnum_map.borrow().iter() {
visit(cstore, dep, ordering);
}
ordering.push(cnum);
@ -196,6 +203,7 @@ impl CStore {
for (&num, _) in self.metas.borrow().iter() {
visit(self, num, &mut ordering);
}
info!("topological ordering: {:?}", ordering);
ordering.reverse();
let mut libs = self.used_crate_sources.borrow()
.iter()
@ -271,8 +279,10 @@ impl crate_metadata {
filemaps
}
}
pub fn with_local_path<T, F>(&self, f: F) -> T
where F: Fn(&[ast_map::PathElem]) -> T {
where F: Fn(&[ast_map::PathElem]) -> T
{
let cpath = self.local_path.borrow();
if cpath.is_empty() {
let name = ast_map::PathMod(token::intern(&self.name));
@ -281,6 +291,7 @@ impl crate_metadata {
f(cpath.as_slice())
}
}
pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) {
let mut cpath = self.local_path.borrow_mut();
let cap = cpath.len();
@ -295,6 +306,16 @@ impl crate_metadata {
},
}
}
pub fn is_allocator(&self) -> bool {
let attrs = decoder::get_crate_attributes(self.data());
attr::contains_name(&attrs, "allocator")
}
pub fn needs_allocator(&self) -> bool {
let attrs = decoder::get_crate_attributes(self.data());
attr::contains_name(&attrs, "needs_allocator")
}
}
impl MetadataBlob {

View file

@ -1174,6 +1174,7 @@ pub struct CrateDep {
pub cnum: ast::CrateNum,
pub name: String,
pub hash: Svh,
pub explicitly_linked: bool,
}
pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
@ -1188,10 +1189,13 @@ pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
let name = docstr(depdoc, tag_crate_dep_crate_name);
let hash = Svh::new(&docstr(depdoc, tag_crate_dep_hash));
let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked);
let explicitly_linked = reader::doc_as_u8(doc) != 0;
CrateDep {
cnum: crate_num as u32 + 1,
name: name,
hash: hash,
explicitly_linked: explicitly_linked,
}
}).collect()
}
@ -1252,7 +1256,7 @@ pub fn translate_def_id(cdata: Cmd, did: ast::DefId) -> ast::DefId {
return ast::DefId { krate: cdata.cnum, node: did.node };
}
match cdata.cnum_map.get(&did.krate) {
match cdata.cnum_map.borrow().get(&did.krate) {
Some(&n) => {
ast::DefId {
krate: n,
@ -1270,7 +1274,7 @@ fn reverse_translate_def_id(cdata: Cmd, did: ast::DefId) -> Option<ast::DefId> {
return Some(ast::DefId { krate: ast::LOCAL_CRATE, node: did.node });
}
for (&local, &global) in &cdata.cnum_map {
for (&local, &global) in cdata.cnum_map.borrow().iter() {
if global == did.krate {
return Some(ast::DefId { krate: local, node: did.node });
}
@ -1385,7 +1389,7 @@ pub fn get_dylib_dependency_formats(cdata: Cmd)
let cnum = spec.split(':').nth(0).unwrap();
let link = spec.split(':').nth(1).unwrap();
let cnum: ast::CrateNum = cnum.parse().unwrap();
let cnum = match cdata.cnum_map.get(&cnum) {
let cnum = match cdata.cnum_map.borrow().get(&cnum) {
Some(&n) => n,
None => panic!("didn't find a crate in the cnum_map")
};

View file

@ -23,8 +23,9 @@ use metadata::cstore;
use metadata::decoder;
use metadata::tyencode;
use middle::def;
use middle::ty::{self, Ty};
use middle::dependency_format::Linkage;
use middle::stability;
use middle::ty::{self, Ty};
use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use serialize::Encodable;
@ -32,6 +33,7 @@ use std::cell::RefCell;
use std::hash::{Hash, Hasher, SipHasher};
use std::io::prelude::*;
use std::io::{Cursor, SeekFrom};
use std::rc::Rc;
use syntax::abi;
use syntax::ast::{self, DefId, NodeId};
use syntax::ast_util::*;
@ -1751,25 +1753,21 @@ fn encode_polarity(rbml_w: &mut Encoder, polarity: ast::ImplPolarity) {
}
fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<decoder::CrateDep> {
fn get_ordered_deps(cstore: &cstore::CStore)
-> Vec<(ast::CrateNum, Rc<cstore::crate_metadata>)> {
// Pull the cnums and name,vers,hash out of cstore
let mut deps = Vec::new();
cstore.iter_crate_data(|key, val| {
let dep = decoder::CrateDep {
cnum: key,
name: decoder::get_crate_name(val.data()),
hash: decoder::get_crate_hash(val.data()),
};
deps.push(dep);
cstore.iter_crate_data(|cnum, val| {
deps.push((cnum, val.clone()));
});
// Sort by cnum
deps.sort_by(|kv1, kv2| kv1.cnum.cmp(&kv2.cnum));
deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0));
// Sanity-check the crate numbers
let mut expected_cnum = 1;
for n in &deps {
assert_eq!(n.cnum, expected_cnum);
for &(n, _) in &deps {
assert_eq!(n, expected_cnum);
expected_cnum += 1;
}
@ -1781,8 +1779,8 @@ fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
// FIXME (#2166): This is not nearly enough to support correct versioning
// but is enough to get transitive crate dependencies working.
rbml_w.start_tag(tag_crate_deps);
for dep in &get_ordered_deps(cstore) {
encode_crate_dep(rbml_w, dep);
for (_cnum, dep) in get_ordered_deps(cstore) {
encode_crate_dep(rbml_w, &dep);
}
rbml_w.end_tag();
}
@ -1985,10 +1983,13 @@ fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) {
}
fn encode_crate_dep(rbml_w: &mut Encoder,
dep: &decoder::CrateDep) {
dep: &cstore::crate_metadata) {
rbml_w.start_tag(tag_crate_dep);
rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name);
rbml_w.wr_tagged_str(tag_crate_dep_hash, dep.hash.as_str());
rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
let hash = decoder::get_crate_hash(dep.data());
rbml_w.wr_tagged_str(tag_crate_dep_hash, hash.as_str());
rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked,
dep.explicitly_linked.get() as u8);
rbml_w.end_tag();
}
@ -2006,13 +2007,16 @@ fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) {
fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
let tag = tag_dylib_dependency_formats;
match ecx.tcx.dependency_formats.borrow().get(&config::CrateTypeDylib) {
match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) {
Some(arr) => {
let s = arr.iter().enumerate().filter_map(|(i, slot)| {
slot.map(|kind| (format!("{}:{}", i + 1, match kind {
cstore::RequireDynamic => "d",
cstore::RequireStatic => "s",
})).to_string())
let kind = match *slot {
Linkage::NotLinked |
Linkage::IncludedFromDylib => return None,
Linkage::Dynamic => "d",
Linkage::Static => "s",
};
Some(format!("{}:{}", i + 1, kind))
}).collect::<Vec<String>>();
rbml_w.wr_tagged_str(tag, &s.join(","));
}

View file

@ -67,7 +67,6 @@ use session;
use session::config;
use metadata::cstore;
use metadata::csearch;
use middle::ty;
use util::nodemap::FnvHashMap;
/// A list of dependencies for a certain crate type.
@ -76,19 +75,29 @@ use util::nodemap::FnvHashMap;
/// The value is None if the crate does not need to be linked (it was found
/// statically in another dylib), or Some(kind) if it needs to be linked as
/// `kind` (either static or dynamic).
pub type DependencyList = Vec<Option<cstore::LinkagePreference>>;
pub type DependencyList = Vec<Linkage>;
/// A mapping of all required dependencies for a particular flavor of output.
///
/// This is local to the tcx, and is generally relevant to one session.
pub type Dependencies = FnvHashMap<config::CrateType, DependencyList>;
pub fn calculate(tcx: &ty::ctxt) {
let mut fmts = tcx.dependency_formats.borrow_mut();
for &ty in tcx.sess.crate_types.borrow().iter() {
fmts.insert(ty, calculate_type(&tcx.sess, ty));
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Linkage {
NotLinked,
IncludedFromDylib,
Static,
Dynamic,
}
pub fn calculate(sess: &session::Session) {
let mut fmts = sess.dependency_formats.borrow_mut();
for &ty in sess.crate_types.borrow().iter() {
let linkage = calculate_type(sess, ty);
verify_ok(sess, &linkage);
fmts.insert(ty, linkage);
}
tcx.sess.abort_if_errors();
sess.abort_if_errors();
}
fn calculate_type(sess: &session::Session,
@ -145,12 +154,12 @@ fn calculate_type(sess: &session::Session,
sess.cstore.iter_crate_data(|cnum, data| {
let src = sess.cstore.get_used_crate_source(cnum).unwrap();
if src.dylib.is_some() {
debug!("adding dylib: {}", data.name);
info!("adding dylib: {}", data.name);
add_library(sess, cnum, cstore::RequireDynamic, &mut formats);
let deps = csearch::get_dylib_dependency_formats(&sess.cstore, cnum);
for &(depnum, style) in &deps {
debug!("adding {:?}: {}", style,
sess.cstore.get_crate_data(depnum).name.clone());
info!("adding {:?}: {}", style,
sess.cstore.get_crate_data(depnum).name.clone());
add_library(sess, depnum, style, &mut formats);
}
}
@ -158,24 +167,36 @@ fn calculate_type(sess: &session::Session,
// Collect what we've got so far in the return vector.
let mut ret = (1..sess.cstore.next_crate_num()).map(|i| {
match formats.get(&i).cloned() {
v @ Some(cstore::RequireDynamic) => v,
_ => None,
match formats.get(&i) {
Some(&cstore::RequireDynamic) => Linkage::Dynamic,
Some(&cstore::RequireStatic) => Linkage::IncludedFromDylib,
None => Linkage::NotLinked,
}
}).collect::<Vec<_>>();
// Run through the dependency list again, and add any missing libraries as
// static libraries.
//
// If the crate hasn't been included yet and it's not actually required
// (e.g. it's an allocator) then we skip it here as well.
sess.cstore.iter_crate_data(|cnum, data| {
let src = sess.cstore.get_used_crate_source(cnum).unwrap();
if src.dylib.is_none() && !formats.contains_key(&cnum) {
if src.dylib.is_none() &&
!formats.contains_key(&cnum) &&
data.explicitly_linked.get() {
assert!(src.rlib.is_some());
debug!("adding staticlib: {}", data.name);
info!("adding staticlib: {}", data.name);
add_library(sess, cnum, cstore::RequireStatic, &mut formats);
ret[cnum as usize - 1] = Some(cstore::RequireStatic);
ret[cnum as usize - 1] = Linkage::Static;
}
});
// We've gotten this far because we're emitting some form of a final
// artifact which means that we're going to need an allocator of some form.
// No allocator may have been required or linked so far, so activate one
// here if one isn't set.
activate_allocator(sess, &mut ret);
// When dylib B links to dylib A, then when using B we must also link to A.
// It could be the case, however, that the rlib for A is present (hence we
// found metadata), but the dylib for A has since been removed.
@ -183,21 +204,22 @@ fn calculate_type(sess: &session::Session,
// For situations like this, we perform one last pass over the dependencies,
// making sure that everything is available in the requested format.
for (cnum, kind) in ret.iter().enumerate() {
let cnum = cnum as ast::CrateNum;
let src = sess.cstore.get_used_crate_source(cnum + 1).unwrap();
let cnum = (cnum + 1) as ast::CrateNum;
let src = sess.cstore.get_used_crate_source(cnum).unwrap();
match *kind {
None => continue,
Some(cstore::RequireStatic) if src.rlib.is_some() => continue,
Some(cstore::RequireDynamic) if src.dylib.is_some() => continue,
Some(kind) => {
let data = sess.cstore.get_crate_data(cnum + 1);
Linkage::NotLinked |
Linkage::IncludedFromDylib => {}
Linkage::Static if src.rlib.is_some() => continue,
Linkage::Dynamic if src.dylib.is_some() => continue,
kind => {
let kind = match kind {
Linkage::Static => "rlib",
_ => "dylib",
};
let data = sess.cstore.get_crate_data(cnum);
sess.err(&format!("crate `{}` required to be available in {}, \
but it was not available in this form",
data.name,
match kind {
cstore::RequireStatic => "rlib",
cstore::RequireDynamic => "dylib",
}));
data.name, kind));
}
}
}
@ -221,8 +243,7 @@ fn add_library(sess: &session::Session,
if link2 != link || link == cstore::RequireStatic {
let data = sess.cstore.get_crate_data(cnum);
sess.err(&format!("cannot satisfy dependencies so `{}` only \
shows up once",
data.name));
shows up once", data.name));
sess.help("having upstream crates all available in one format \
will likely make this go away");
}
@ -233,9 +254,79 @@ fn add_library(sess: &session::Session,
fn attempt_static(sess: &session::Session) -> Option<DependencyList> {
let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
if crates.iter().by_ref().all(|&(_, ref p)| p.is_some()) {
Some(crates.into_iter().map(|_| Some(cstore::RequireStatic)).collect())
} else {
None
if !crates.iter().by_ref().all(|&(_, ref p)| p.is_some()) {
return None
}
// All crates are available in an rlib format, so we're just going to link
// everything in explicitly so long as it's actually required.
let mut ret = (1..sess.cstore.next_crate_num()).map(|cnum| {
if sess.cstore.get_crate_data(cnum).explicitly_linked.get() {
Linkage::Static
} else {
Linkage::NotLinked
}
}).collect::<Vec<_>>();
// Our allocator may not have been activated as it's not flagged with
// explicitly_linked, so flag it here if necessary.
activate_allocator(sess, &mut ret);
Some(ret)
}
// Given a list of how to link upstream dependencies so far, ensure that an
// allocator is activated. This will not do anything if one was transitively
// included already (e.g. via a dylib or explicitly so).
//
// If an allocator was not found then we're guaranteed the metadata::creader
// module has injected an allocator dependency (not listed as a required
// dependency) in the session's `injected_allocator` field. If this field is not
// set then this compilation doesn't actually need an allocator and we can also
// skip this step entirely.
fn activate_allocator(sess: &session::Session, list: &mut DependencyList) {
let mut allocator_found = false;
for (i, slot) in list.iter().enumerate() {
let cnum = (i + 1) as ast::CrateNum;
if !sess.cstore.get_crate_data(cnum).is_allocator() {
continue
}
if let Linkage::NotLinked = *slot {
continue
}
allocator_found = true;
}
if !allocator_found {
if let Some(injected_allocator) = sess.injected_allocator.get() {
let idx = injected_allocator as usize - 1;
assert_eq!(list[idx], Linkage::NotLinked);
list[idx] = Linkage::Static;
}
}
}
// After the linkage for a crate has been determined we need to verify that
// there's only going to be one allocator in the output.
fn verify_ok(sess: &session::Session, list: &[Linkage]) {
if list.len() == 0 {
return
}
let mut allocator = None;
for (i, linkage) in list.iter().enumerate() {
let cnum = (i + 1) as ast::CrateNum;
let data = sess.cstore.get_crate_data(cnum);
if !data.is_allocator() {
continue
}
if let Linkage::NotLinked = *linkage {
continue
}
if let Some(prev_alloc) = allocator {
let prev = sess.cstore.get_crate_data(prev_alloc);
sess.err(&format!("cannot link together two \
allocators: {} and {}",
prev.name(), data.name()));
}
allocator = Some(cnum);
}
}

View file

@ -47,7 +47,6 @@ use middle::check_const;
use middle::const_eval::{self, ConstVal, ErrKind};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::def::{self, DefMap, ExportMap};
use middle::dependency_format;
use middle::fast_reject;
use middle::free_region::FreeRegionMap;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
@ -840,8 +839,6 @@ pub struct ctxt<'tcx> {
pub extern_const_variants: RefCell<DefIdMap<ast::NodeId>>,
pub extern_const_fns: RefCell<DefIdMap<ast::NodeId>>,
pub dependency_formats: RefCell<dependency_format::Dependencies>,
pub node_lint_levels: RefCell<FnvHashMap<(ast::NodeId, lint::LintId),
lint::LevelSource>>,
@ -3837,7 +3834,6 @@ impl<'tcx> ctxt<'tcx> {
extern_const_statics: RefCell::new(DefIdMap()),
extern_const_variants: RefCell::new(DefIdMap()),
extern_const_fns: RefCell::new(DefIdMap()),
dependency_formats: RefCell::new(FnvHashMap()),
node_lint_levels: RefCell::new(FnvHashMap()),
transmute_restrictions: RefCell::new(Vec::new()),
stability: RefCell::new(stability),

View file

@ -11,8 +11,9 @@
use lint;
use metadata::cstore::CStore;
use metadata::filesearch;
use middle::dependency_format;
use session::search_paths::PathKind;
use util::nodemap::NodeMap;
use util::nodemap::{NodeMap, FnvHashMap};
use syntax::ast::NodeId;
use syntax::codemap::Span;
@ -57,6 +58,7 @@ pub struct Session {
pub plugin_llvm_passes: RefCell<Vec<String>>,
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub dependency_formats: RefCell<dependency_format::Dependencies>,
pub crate_metadata: RefCell<Vec<String>>,
pub features: RefCell<feature_gate::Features>,
@ -68,7 +70,11 @@ pub struct Session {
pub can_print_warnings: bool,
next_node_id: Cell<ast::NodeId>
/// The metadata::creader module may inject an allocator dependency if it
/// didn't already find one, and this tracks what was injected.
pub injected_allocator: Cell<Option<ast::CrateNum>>,
next_node_id: Cell<ast::NodeId>,
}
impl Session {
@ -447,12 +453,14 @@ pub fn build_session_(sopts: config::Options,
plugin_llvm_passes: RefCell::new(Vec::new()),
plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
dependency_formats: RefCell::new(FnvHashMap()),
crate_metadata: RefCell::new(Vec::new()),
delayed_span_bug: RefCell::new(None),
features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
can_print_warnings: can_print_warnings,
next_node_id: Cell::new(1)
next_node_id: Cell::new(1),
injected_allocator: Cell::new(None),
};
sess

View file

@ -32,11 +32,11 @@ pub const FN_OUTPUT_NAME: &'static str = "Output";
#[derive(Clone, Copy, Debug)]
pub struct ErrorReported;
pub fn time<T, U, F>(do_it: bool, what: &str, u: U, f: F) -> T where
F: FnOnce(U) -> T,
pub fn time<T, F>(do_it: bool, what: &str, f: F) -> T where
F: FnOnce() -> T,
{
thread_local!(static DEPTH: Cell<usize> = Cell::new(0));
if !do_it { return f(u); }
if !do_it { return f(); }
let old = DEPTH.with(|slot| {
let r = slot.get();
@ -49,7 +49,7 @@ pub fn time<T, U, F>(do_it: bool, what: &str, u: U, f: F) -> T where
let ref mut rvp = rv;
Duration::span(move || {
*rvp = Some(f(u))
*rvp = Some(f())
})
};
let rv = rv.unwrap();

View file

@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions {
dll_suffix: ".dylib".to_string(),
archive_format: "bsd".to_string(),
pre_link_args: Vec::new(),
exe_allocation_crate: super::best_allocator(),
.. Default::default()
}
}

View file

@ -20,6 +20,7 @@ pub fn opts() -> TargetOptions {
has_rpath: true,
position_independent_executables: true,
archive_format: "gnu".to_string(),
exe_allocation_crate: super::best_allocator(),
.. Default::default()
}

View file

@ -29,6 +29,7 @@ pub fn opts() -> TargetOptions {
),
position_independent_executables: true,
archive_format: "bsd".to_string(),
exe_allocation_crate: super::best_allocator(),
.. Default::default()
}
}

View file

@ -18,6 +18,7 @@ pub fn opts() -> TargetOptions {
executables: true,
has_rpath: true,
archive_format: "gnu".to_string(),
exe_allocation_crate: super::best_allocator(),
.. Default::default()
}

View file

@ -29,6 +29,7 @@ pub fn opts() -> TargetOptions {
],
position_independent_executables: true,
archive_format: "gnu".to_string(),
exe_allocation_crate: super::best_allocator(),
.. Default::default()
}
}

View file

@ -173,6 +173,10 @@ pub struct TargetOptions {
/// defined in libgcc. If this option is enabled, the target must provide
/// `eh_unwind_resume` lang item.
pub custom_unwind_resume: bool,
/// Default crate for allocation symbols to link against
pub lib_allocation_crate: String,
pub exe_allocation_crate: String,
}
impl Default for TargetOptions {
@ -211,6 +215,8 @@ impl Default for TargetOptions {
post_link_objects: Vec::new(),
archive_format: String::new(),
custom_unwind_resume: false,
lib_allocation_crate: "alloc_system".to_string(),
exe_allocation_crate: "alloc_system".to_string(),
}
}
}
@ -424,3 +430,11 @@ impl Target {
Err(format!("Could not find specification for target {:?}", target))
}
}
fn best_allocator() -> String {
if cfg!(disable_jemalloc) {
"alloc_system".to_string()
} else {
"alloc_jemalloc".to_string()
}
}

View file

@ -27,6 +27,7 @@ pub fn opts() -> TargetOptions {
),
position_independent_executables: true,
archive_format: "gnu".to_string(),
exe_allocation_crate: super::best_allocator(),
.. Default::default()
}
}

View file

@ -60,6 +60,7 @@ pub fn opts() -> TargetOptions {
// Always enable DEP (NX bit) when it is available
"-Wl,--nxcompat".to_string(),
),
exe_allocation_crate: super::best_allocator(),
.. Default::default()
}

View file

@ -60,6 +60,7 @@ pub fn opts() -> TargetOptions {
"/NXCOMPAT".to_string(),
],
archive_format: "gnu".to_string(),
exe_allocation_crate: super::best_allocator(),
.. Default::default()
}

View file

@ -356,7 +356,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
syntax::ext::mtwt::reset_tables();
token::reset_ident_interner();
let krate = time(sess.time_passes(), "parsing", (), |_| {
let krate = time(sess.time_passes(), "parsing", || {
match *input {
Input::File(ref file) => {
parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess)
@ -406,7 +406,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
//
// baz! should not use this definition unless foo is enabled.
krate = time(time_passes, "configuration 1", krate, |krate|
krate = time(time_passes, "configuration 1", move ||
syntax::config::strip_unconfigured_items(sess.diagnostic(), krate));
*sess.crate_types.borrow_mut() =
@ -414,11 +414,11 @@ pub fn phase_2_configure_and_expand(sess: &Session,
*sess.crate_metadata.borrow_mut() =
collect_crate_metadata(sess, &krate.attrs);
time(time_passes, "recursion limit", (), |_| {
time(time_passes, "recursion limit", || {
middle::recursion_limit::update_recursion_limit(sess, &krate);
});
time(time_passes, "gated macro checking", (), |_| {
time(time_passes, "gated macro checking", || {
let features =
syntax::feature_gate::check_crate_macros(sess.codemap(),
&sess.parse_sess.span_diagnostic,
@ -430,20 +430,20 @@ pub fn phase_2_configure_and_expand(sess: &Session,
});
krate = time(time_passes, "crate injection", krate, |krate|
krate = time(time_passes, "crate injection", ||
syntax::std_inject::maybe_inject_crates_ref(krate,
sess.opts.alt_std_name.clone()));
let macros = time(time_passes, "macro loading", (), |_|
let macros = time(time_passes, "macro loading", ||
metadata::macro_import::read_macro_defs(sess, &krate));
let mut addl_plugins = Some(addl_plugins);
let registrars = time(time_passes, "plugin loading", (), |_|
let registrars = time(time_passes, "plugin loading", ||
plugin::load::load_plugins(sess, &krate, addl_plugins.take().unwrap()));
let mut registry = Registry::new(sess, &krate);
time(time_passes, "plugin registration", registrars, |registrars| {
time(time_passes, "plugin registration", || {
if sess.features.borrow().rustc_diagnostic_macros {
registry.register_macro("__diagnostic_used",
diagnostics::plugin::expand_diagnostic_used);
@ -486,45 +486,43 @@ pub fn phase_2_configure_and_expand(sess: &Session,
// Abort if there are errors from lint processing or a plugin registrar.
sess.abort_if_errors();
krate = time(time_passes, "expansion", (krate, macros, syntax_exts),
|(krate, macros, syntax_exts)| {
// Windows dlls do not have rpaths, so they don't know how to find their
// dependencies. It's up to us to tell the system where to find all the
// dependent dlls. Note that this uses cfg!(windows) as opposed to
// targ_cfg because syntax extensions are always loaded for the host
// compiler, not for the target.
let mut _old_path = OsString::new();
if cfg!(windows) {
_old_path = env::var_os("PATH").unwrap_or(_old_path);
let mut new_path = sess.host_filesearch(PathKind::All)
.get_dylib_search_paths();
new_path.extend(env::split_paths(&_old_path));
env::set_var("PATH", &env::join_paths(new_path).unwrap());
}
let features = sess.features.borrow();
let cfg = syntax::ext::expand::ExpansionConfig {
crate_name: crate_name.to_string(),
features: Some(&features),
recursion_limit: sess.recursion_limit.get(),
trace_mac: sess.opts.debugging_opts.trace_macros,
};
let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
cfg,
macros,
syntax_exts,
krate);
if cfg!(windows) {
env::set_var("PATH", &_old_path);
}
ret
krate = time(time_passes, "expansion", || {
// Windows dlls do not have rpaths, so they don't know how to find their
// dependencies. It's up to us to tell the system where to find all the
// dependent dlls. Note that this uses cfg!(windows) as opposed to
// targ_cfg because syntax extensions are always loaded for the host
// compiler, not for the target.
let mut _old_path = OsString::new();
if cfg!(windows) {
_old_path = env::var_os("PATH").unwrap_or(_old_path);
let mut new_path = sess.host_filesearch(PathKind::All)
.get_dylib_search_paths();
new_path.extend(env::split_paths(&_old_path));
env::set_var("PATH", &env::join_paths(new_path).unwrap());
}
);
let features = sess.features.borrow();
let cfg = syntax::ext::expand::ExpansionConfig {
crate_name: crate_name.to_string(),
features: Some(&features),
recursion_limit: sess.recursion_limit.get(),
trace_mac: sess.opts.debugging_opts.trace_macros,
};
let ret = syntax::ext::expand::expand_crate(&sess.parse_sess,
cfg,
macros,
syntax_exts,
krate);
if cfg!(windows) {
env::set_var("PATH", &_old_path);
}
ret
});
// Needs to go *after* expansion to be able to check the results
// of macro expansion. This runs before #[cfg] to try to catch as
// much as possible (e.g. help the programmer avoid platform
// specific differences)
time(time_passes, "complete gated feature checking 1", (), |_| {
time(time_passes, "complete gated feature checking 1", || {
let features =
syntax::feature_gate::check_crate(sess.codemap(),
&sess.parse_sess.span_diagnostic,
@ -537,25 +535,25 @@ pub fn phase_2_configure_and_expand(sess: &Session,
// JBC: make CFG processing part of expansion to avoid this problem:
// strip again, in case expansion added anything with a #[cfg].
krate = time(time_passes, "configuration 2", krate, |krate|
krate = time(time_passes, "configuration 2", ||
syntax::config::strip_unconfigured_items(sess.diagnostic(), krate));
krate = time(time_passes, "maybe building test harness", krate, |krate|
krate = time(time_passes, "maybe building test harness", ||
syntax::test::modify_for_testing(&sess.parse_sess,
&sess.opts.cfg,
krate,
sess.diagnostic()));
krate = time(time_passes, "prelude injection", krate, |krate|
krate = time(time_passes, "prelude injection", ||
syntax::std_inject::maybe_inject_prelude(&sess.parse_sess, krate));
time(time_passes, "checking that all macro invocations are gone", &krate, |krate|
syntax::ext::expand::check_for_macros(&sess.parse_sess, krate));
time(time_passes, "checking that all macro invocations are gone", ||
syntax::ext::expand::check_for_macros(&sess.parse_sess, &krate));
// One final feature gating of the true AST that gets compiled
// later, to make sure we've got everything (e.g. configuration
// can insert new attributes via `cfg_attr`)
time(time_passes, "complete gated feature checking 2", (), |_| {
time(time_passes, "complete gated feature checking 2", || {
let features =
syntax::feature_gate::check_crate(sess.codemap(),
&sess.parse_sess.span_diagnostic,
@ -582,7 +580,7 @@ pub fn assign_node_ids_and_map<'ast>(sess: &Session,
}
}
let map = time(sess.time_passes(), "assigning node ids and indexing ast", forest, |forest|
let map = time(sess.time_passes(), "assigning node ids and indexing ast", move ||
ast_map::map_crate(forest, NodeIdAssigner { sess: sess }));
if sess.opts.debugging_opts.ast_json {
@ -608,10 +606,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
let time_passes = sess.time_passes();
let krate = ast_map.krate();
time(time_passes, "external crate/lib resolution", (), |_|
time(time_passes, "external crate/lib resolution", ||
LocalCrateReader::new(&sess, &ast_map).read_crates(krate));
let lang_items = time(time_passes, "language item collection", (), |_|
let lang_items = time(time_passes, "language item collection", ||
middle::lang_items::collect_language_items(krate, &sess));
let resolve::CrateMap {
@ -622,30 +620,30 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
external_exports,
glob_map,
} =
time(time_passes, "resolution", (),
|_| resolve::resolve_crate(&sess, &ast_map, make_glob_map));
time(time_passes, "resolution",
|| resolve::resolve_crate(&sess, &ast_map, make_glob_map));
// Discard MTWT tables that aren't required past resolution.
syntax::ext::mtwt::clear_tables();
let named_region_map = time(time_passes, "lifetime resolution", (),
|_| middle::resolve_lifetime::krate(&sess, krate, &def_map));
let named_region_map = time(time_passes, "lifetime resolution",
|| middle::resolve_lifetime::krate(&sess, krate, &def_map));
time(time_passes, "looking for entry point", (),
|_| middle::entry::find_entry_point(&sess, &ast_map));
time(time_passes, "looking for entry point",
|| middle::entry::find_entry_point(&sess, &ast_map));
sess.plugin_registrar_fn.set(
time(time_passes, "looking for plugin registrar", (), |_|
time(time_passes, "looking for plugin registrar", ||
plugin::build::find_plugin_registrar(
sess.diagnostic(), krate)));
let region_map = time(time_passes, "region resolution", (), |_|
let region_map = time(time_passes, "region resolution", ||
middle::region::resolve_crate(&sess, krate));
time(time_passes, "loop checking", (), |_|
time(time_passes, "loop checking", ||
middle::check_loop::check_crate(&sess, krate));
time(time_passes, "static item recursion checking", (), |_|
time(time_passes, "static item recursion checking", ||
middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
ty::ctxt::create_and_enter(sess,
@ -662,33 +660,33 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
// passes are timed inside typeck
typeck::check_crate(tcx, trait_map);
time(time_passes, "const checking", (), |_|
time(time_passes, "const checking", ||
middle::check_const::check_crate(tcx));
let (exported_items, public_items) =
time(time_passes, "privacy checking", (), |_|
time(time_passes, "privacy checking", ||
rustc_privacy::check_crate(tcx, &export_map, external_exports));
// Do not move this check past lint
time(time_passes, "stability index", (), |_|
time(time_passes, "stability index", ||
tcx.stability.borrow_mut().build(tcx, krate, &public_items));
time(time_passes, "intrinsic checking", (), |_|
time(time_passes, "intrinsic checking", ||
middle::intrinsicck::check_crate(tcx));
time(time_passes, "effect checking", (), |_|
time(time_passes, "effect checking", ||
middle::effect::check_crate(tcx));
time(time_passes, "match checking", (), |_|
time(time_passes, "match checking", ||
middle::check_match::check_crate(tcx));
time(time_passes, "liveness checking", (), |_|
time(time_passes, "liveness checking", ||
middle::liveness::check_crate(tcx));
time(time_passes, "borrow checking", (), |_|
time(time_passes, "borrow checking", ||
borrowck::check_crate(tcx));
time(time_passes, "rvalue checking", (), |_|
time(time_passes, "rvalue checking", ||
middle::check_rvalues::check_crate(tcx, krate));
// Avoid overwhelming user with errors if type checking failed.
@ -699,24 +697,24 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
tcx.sess.abort_if_errors();
let reachable_map =
time(time_passes, "reachability checking", (), |_|
time(time_passes, "reachability checking", ||
reachable::find_reachable(tcx, &exported_items));
time(time_passes, "death checking", (), |_| {
time(time_passes, "death checking", || {
middle::dead::check_crate(tcx,
&exported_items,
&reachable_map)
});
let ref lib_features_used =
time(time_passes, "stability checking", (), |_|
time(time_passes, "stability checking", ||
stability::check_unstable_api_usage(tcx));
time(time_passes, "unused lib feature checking", (), |_|
time(time_passes, "unused lib feature checking", ||
stability::check_unused_or_stable_features(
&tcx.sess, lib_features_used));
time(time_passes, "lint checking", (), |_|
time(time_passes, "lint checking", ||
lint::check_crate(tcx, &exported_items));
// The above three passes generate errors w/o aborting
@ -739,11 +737,11 @@ pub fn phase_4_translate_to_llvm(tcx: &ty::ctxt, analysis: ty::CrateAnalysis)
-> trans::CrateTranslation {
let time_passes = tcx.sess.time_passes();
time(time_passes, "resolving dependency formats", (), |_|
dependency_format::calculate(tcx));
time(time_passes, "resolving dependency formats", ||
dependency_format::calculate(&tcx.sess));
// Option dance to work around the lack of stack once closures.
time(time_passes, "translation", analysis, |analysis|
time(time_passes, "translation", move ||
trans::trans_crate(tcx, analysis))
}
@ -755,7 +753,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
if sess.opts.cg.no_integrated_as {
let output_type = config::OutputTypeAssembly;
time(sess.time_passes(), "LLVM passes", (), |_|
time(sess.time_passes(), "LLVM passes", ||
write::run_passes(sess, trans, &[output_type], outputs));
write::run_assembler(sess, outputs);
@ -765,7 +763,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
fs::remove_file(&outputs.temp_path(config::OutputTypeAssembly)).unwrap();
}
} else {
time(sess.time_passes(), "LLVM passes", (), |_|
time(sess.time_passes(), "LLVM passes", ||
write::run_passes(sess,
trans,
&sess.opts.output_types,
@ -780,7 +778,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
pub fn phase_6_link_output(sess: &Session,
trans: &trans::CrateTranslation,
outputs: &OutputFilenames) {
time(sess.time_passes(), "linking", (), |_|
time(sess.time_passes(), "linking", ||
link::link_binary(sess,
trans,
outputs,

View file

@ -383,10 +383,10 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
if sess.opts.debugging_opts.save_analysis {
control.after_analysis.callback = box |state| {
time(state.session.time_passes(),
"save analysis", (),
|_| save::process_crate(state.tcx.unwrap(),
state.analysis.unwrap(),
state.out_dir));
"save analysis",
|| save::process_crate(state.tcx.unwrap(),
state.analysis.unwrap(),
state.out_dir));
};
control.make_glob_map = resolve::MakeGlobMap::Yes;
}

View file

@ -23,6 +23,7 @@ use metadata::common::LinkMeta;
use metadata::filesearch::FileDoesntMatch;
use metadata::loader::METADATA_FILENAME;
use metadata::{encoder, cstore, filesearch, csearch, creader};
use middle::dependency_format::Linkage;
use middle::ty::{self, Ty};
use rustc::ast_map::{PathElem, PathElems, PathName};
use trans::{CrateContext, CrateTranslation, gensym_name};
@ -493,6 +494,31 @@ pub fn filename_for_input(sess: &Session,
}
}
pub fn each_linked_rlib(sess: &Session,
f: &mut FnMut(ast::CrateNum, &Path)) {
let crates = sess.cstore.get_used_crates(cstore::RequireStatic).into_iter();
let fmts = sess.dependency_formats.borrow();
let fmts = fmts.get(&config::CrateTypeExecutable).or_else(|| {
fmts.get(&config::CrateTypeStaticlib)
}).unwrap_or_else(|| {
sess.bug("could not find formats for rlibs")
});
for (cnum, path) in crates {
match fmts[cnum as usize - 1] {
Linkage::NotLinked | Linkage::IncludedFromDylib => continue,
_ => {}
}
let name = sess.cstore.get_crate_data(cnum).name.clone();
let path = match path {
Some(p) => p,
None => {
sess.fatal(&format!("could not find rlib for: `{}`", name));
}
};
f(cnum, &path);
}
}
fn link_binary_output(sess: &Session,
trans: &CrateTranslation,
crate_type: config::CrateType,
@ -524,11 +550,11 @@ fn link_binary_output(sess: &Session,
link_staticlib(sess, &objects, &out_filename, tmpdir.path());
}
config::CrateTypeExecutable => {
link_natively(sess, trans, false, &objects, &out_filename, outputs,
link_natively(sess, false, &objects, &out_filename, trans, outputs,
tmpdir.path());
}
config::CrateTypeDylib => {
link_natively(sess, trans, true, &objects, &out_filename, outputs,
link_natively(sess, true, &objects, &out_filename, trans, outputs,
tmpdir.path());
}
}
@ -763,23 +789,15 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
ab.add_native_library("compiler-rt").unwrap();
}
let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
let mut all_native_libs = vec![];
for &(cnum, ref path) in &crates {
let ref name = sess.cstore.get_crate_data(cnum).name;
let p = match *path {
Some(ref p) => p.clone(), None => {
sess.err(&format!("could not find rlib for: `{}`",
name));
continue
}
};
ab.add_rlib(&p, &name[..], sess.lto()).unwrap();
each_linked_rlib(sess, &mut |cnum, path| {
let name = sess.cstore.get_crate_data(cnum).name();
ab.add_rlib(path, &name, sess.lto()).unwrap();
let native_libs = csearch::get_native_libraries(&sess.cstore, cnum);
all_native_libs.extend(native_libs);
}
});
ab.update_symbols();
ab.build();
@ -805,8 +823,9 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
//
// This will invoke the system linker/cc to create the resulting file. This
// links to all upstream files as well.
fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
fn link_natively(sess: &Session, dylib: bool,
objects: &[PathBuf], out_filename: &Path,
trans: &CrateTranslation,
outputs: &OutputFilenames,
tmpdir: &Path) {
info!("preparing dylib? ({}) from {:?} to {:?}", dylib, objects,
@ -829,7 +848,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
};
link_args(&mut *linker, sess, dylib, tmpdir,
trans, objects, out_filename, outputs);
objects, out_filename, trans, outputs);
if !sess.target.target.options.no_compiler_rt {
linker.link_staticlib("compiler-rt");
}
@ -848,7 +867,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
// Invoke the system linker
info!("{:?}", &cmd);
let prog = time(sess.time_passes(), "running linker", (), |()| cmd.output());
let prog = time(sess.time_passes(), "running linker", || cmd.output());
match prog {
Ok(prog) => {
if !prog.status.success() {
@ -884,9 +903,9 @@ fn link_args(cmd: &mut Linker,
sess: &Session,
dylib: bool,
tmpdir: &Path,
trans: &CrateTranslation,
objects: &[PathBuf],
out_filename: &Path,
trans: &CrateTranslation,
outputs: &OutputFilenames) {
// The default library location, we need this to find the runtime.
@ -980,7 +999,7 @@ fn link_args(cmd: &mut Linker,
// this kind of behavior is pretty platform specific and generally not
// recommended anyway, so I don't think we're shooting ourself in the foot
// much with that.
add_upstream_rust_crates(cmd, sess, dylib, tmpdir, trans);
add_upstream_rust_crates(cmd, sess, dylib, tmpdir);
add_local_native_libraries(cmd, sess);
add_upstream_native_libraries(cmd, sess);
@ -1086,8 +1105,7 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
// dependencies will be linked when producing the final output (instead of
// the intermediate rlib version)
fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
dylib: bool, tmpdir: &Path,
trans: &CrateTranslation) {
dylib: bool, tmpdir: &Path) {
// All of the heavy lifting has previously been accomplished by the
// dependency_format module of the compiler. This is just crawling the
// output of that module, adding crates as necessary.
@ -1096,10 +1114,11 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
// will slurp up the object files inside), and linking to a dynamic library
// involves just passing the right -l flag.
let formats = sess.dependency_formats.borrow();
let data = if dylib {
trans.crate_formats.get(&config::CrateTypeDylib).unwrap()
formats.get(&config::CrateTypeDylib).unwrap()
} else {
trans.crate_formats.get(&config::CrateTypeExecutable).unwrap()
formats.get(&config::CrateTypeExecutable).unwrap()
};
// Invoke get_used_crates to ensure that we get a topological sorting of
@ -1110,20 +1129,17 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
// We may not pass all crates through to the linker. Some crates may
// appear statically in an existing dylib, meaning we'll pick up all the
// symbols from the dylib.
let kind = match data[cnum as usize - 1] {
Some(t) => t,
None => continue
};
let src = sess.cstore.get_used_crate_source(cnum).unwrap();
match kind {
cstore::RequireDynamic => {
add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0)
}
cstore::RequireStatic => {
match data[cnum as usize - 1] {
Linkage::NotLinked |
Linkage::IncludedFromDylib => {}
Linkage::Static => {
add_static_crate(cmd, sess, tmpdir, dylib, &src.rlib.unwrap().0)
}
Linkage::Dynamic => {
add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0)
}
}
}
// Converts a library file-stem into a cc -l argument
@ -1174,7 +1190,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
let name = cratepath.file_name().unwrap().to_str().unwrap();
let name = &name[3..name.len() - 5]; // chop off lib/.rlib
time(sess.time_passes(), &format!("altering {}.rlib", name), (), |()| {
time(sess.time_passes(), &format!("altering {}.rlib", name), || {
let cfg = archive_config(sess, &dst, Some(cratepath));
let mut archive = ArchiveBuilder::new(cfg);
archive.remove_file(METADATA_FILENAME);

View file

@ -17,7 +17,7 @@ use std::process::Command;
use back::archive;
use metadata::csearch;
use metadata::cstore;
use middle::dependency_format::Linkage;
use session::Session;
use session::config::DebugInfoLevel::{NoDebugInfo, LimitedDebugInfo, FullDebugInfo};
use session::config::CrateTypeDylib;
@ -347,9 +347,10 @@ impl<'a> Linker for MsvcLinker<'a> {
// dynamic library. For all statically linked libraries we take all
// their reachable symbols and emit them as well.
let cstore = &sess.cstore;
let symbols = trans.crate_formats[&CrateTypeDylib].iter();
let formats = sess.dependency_formats.borrow();
let symbols = formats[&CrateTypeDylib].iter();
let symbols = symbols.enumerate().filter_map(|(i, f)| {
if let Some(cstore::RequireStatic) = *f {
if *f == Linkage::Static {
Some((i + 1) as ast::CrateNum)
} else {
None

View file

@ -14,7 +14,6 @@ use rustc::session::{self, config};
use llvm;
use llvm::archive_ro::ArchiveRO;
use llvm::{ModuleRef, TargetMachineRef, True, False};
use rustc::metadata::cstore;
use rustc::util::common::time;
use back::write::{ModuleConfig, with_llvm_pmb};
@ -46,17 +45,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
// For each of our upstream dependencies, find the corresponding rlib and
// load the bitcode from the archive. Then merge it into the current LLVM
// module that we've got.
let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
for (cnum, path) in crates {
let name = sess.cstore.get_crate_data(cnum).name.clone();
let path = match path {
Some(p) => p,
None => {
sess.fatal(&format!("could not find rlib for: `{}`",
name));
}
};
link::each_linked_rlib(sess, &mut |_, path| {
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
let bytecodes = archive.iter().filter_map(|child| {
child.name().map(|name| (name, child))
@ -65,7 +54,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
let bc_encoded = data.data();
let bc_decoded = if is_versioned_bytecode_format(bc_encoded) {
time(sess.time_passes(), &format!("decode {}", name), (), |_| {
time(sess.time_passes(), &format!("decode {}", name), || {
// Read the version
let version = extract_bytecode_format_version(bc_encoded);
@ -89,9 +78,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
}
})
} else {
time(sess.time_passes(), &format!("decode {}", name), (), |_| {
// the object must be in the old, pre-versioning format, so simply
// inflate everything and let LLVM decide if it can make sense of it
time(sess.time_passes(), &format!("decode {}", name), || {
// the object must be in the old, pre-versioning format, so
// simply inflate everything and let LLVM decide if it can
// make sense of it
match flate::inflate_bytes(bc_encoded) {
Ok(bc) => bc,
Err(_) => {
@ -104,8 +94,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
let ptr = bc_decoded.as_ptr();
debug!("linking {}", name);
time(sess.time_passes(), &format!("ll link {}", name), (),
|()| unsafe {
time(sess.time_passes(), &format!("ll link {}", name), || unsafe {
if !llvm::LLVMRustLinkInExternalBitcode(llmod,
ptr as *const libc::c_char,
bc_decoded.len() as libc::size_t) {
@ -115,7 +104,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
}
});
}
}
});
// Internalize everything but the reachable symbols of the current module
let cstrs: Vec<CString> = reachable.iter().map(|s| {
@ -154,7 +143,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
time(sess.time_passes(), "LTO passes", (), |()|
time(sess.time_passes(), "LTO passes", ||
llvm::LLVMRunPassManager(pm, llmod));
llvm::LLVMDisposePassManager(pm);

View file

@ -484,9 +484,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
cgcx.handler.abort_if_errors();
// Finally, run the actual optimization passes
time(config.time_passes, "llvm function passes", (), |()|
time(config.time_passes, "llvm function passes", ||
llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
time(config.time_passes, "llvm module passes", (), |()|
time(config.time_passes, "llvm module passes", ||
llvm::LLVMRunPassManager(mpm, llmod));
// Deallocate managers that we're now done with
@ -495,7 +495,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
match cgcx.lto_ctxt {
Some((sess, reachable)) if sess.lto() => {
time(sess.time_passes(), "all lto passes", (), |()|
time(sess.time_passes(), "all lto passes", ||
lto::run(sess, llmod, tm, reachable, &config));
if config.emit_lto_bc {
@ -536,7 +536,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}
time(config.time_passes, "codegen passes", (), |()| {
time(config.time_passes, "codegen passes", || {
if config.emit_ir {
let ext = format!("{}.ll", name_extra);
let out = output_names.with_extension(&ext);

View file

@ -2822,7 +2822,6 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat
llcx: shared_ccx.metadata_llcx(),
llmod: shared_ccx.metadata_llmod(),
};
let formats = shared_ccx.tcx().dependency_formats.borrow().clone();
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
CrateTranslation {
@ -2831,7 +2830,6 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat
link: link_meta,
metadata: metadata,
reachable: reachable_symbols,
crate_formats: formats,
no_builtins: no_builtins,
}
}

View file

@ -10,7 +10,6 @@
use llvm::{ContextRef, ModuleRef};
use metadata::common::LinkMeta;
use middle::dependency_format;
pub use self::base::trans_crate;
pub use self::context::CrateContext;
@ -74,6 +73,5 @@ pub struct CrateTranslation {
pub link: LinkMeta,
pub metadata: Vec<u8>,
pub reachable: Vec<String>,
pub crate_formats: dependency_format::Dependencies,
pub no_builtins: bool,
}

View file

@ -332,34 +332,34 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) {
tcx: tcx
};
time(time_passes, "type collecting", (), |_|
time(time_passes, "type collecting", ||
collect::collect_item_types(tcx));
// this ensures that later parts of type checking can assume that items
// have valid types and not error
tcx.sess.abort_if_errors();
time(time_passes, "variance inference", (), |_|
time(time_passes, "variance inference", ||
variance::infer_variance(tcx));
time(time_passes, "coherence checking", (), |_|
time(time_passes, "coherence checking", ||
coherence::check_coherence(&ccx));
time(time_passes, "wf checking (old)", (), |_|
time(time_passes, "wf checking (old)", ||
check::check_wf_old(&ccx));
time(time_passes, "item-types checking", (), |_|
time(time_passes, "item-types checking", ||
check::check_item_types(&ccx));
time(time_passes, "item-bodies checking", (), |_|
time(time_passes, "item-bodies checking", ||
check::check_item_bodies(&ccx));
time(time_passes, "drop-impl checking", (), |_|
time(time_passes, "drop-impl checking", ||
check::check_drop_impls(&ccx));
// Do this last so that if there are errors in the old code, they
// get reported, and we don't get extra warnings.
time(time_passes, "wf checking (new)", (), |_|
time(time_passes, "wf checking (new)", ||
check::check_wf_new(&ccx));
check_for_entry_fn(&ccx);

View file

@ -275,8 +275,6 @@ extern crate alloc;
extern crate rustc_unicode;
extern crate libc;
#[macro_use] #[no_link] extern crate rustc_bitflags;
// Make std testable by not duplicating lang items and other globals. See #2912
#[cfg(test)] extern crate std as realstd;

View file

@ -85,6 +85,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
("on_unimplemented", "1.0.0", Active),
("simd_ffi", "1.0.0", Active),
("allocator", "1.0.0", Active),
("needs_allocator", "1.4.0", Active),
("linked_from", "1.3.0", Active),
("if_let", "1.0.0", Accepted),
@ -253,6 +254,9 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
is an experimental feature")),
("allocator", Gated("allocator",
"the `#[allocator]` attribute is an experimental feature")),
("needs_allocator", Gated("needs_allocator", "the `#[needs_allocator]` \
attribute is an experimental \
feature")),
("rustc_variance", Gated("rustc_attrs",
"the `#[rustc_variance]` attribute \
is an experimental feature")),

View file

@ -0,0 +1,55 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![feature(allocator, no_std, core, core_intrinsics, libc)]
#![allocator]
#![crate_type = "rlib"]
#![no_std]
extern crate libc;
pub static mut HITS: usize = 0;
#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
unsafe {
HITS += 1;
libc::malloc(size as libc::size_t) as *mut u8
}
}
#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
unsafe {
HITS += 1;
libc::free(ptr as *mut _)
}
}
#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
align: usize) -> *mut u8 {
unsafe {
libc::realloc(ptr as *mut _, size as libc::size_t) as *mut u8
}
}
#[no_mangle]
pub extern fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize,
size: usize, align: usize) -> usize {
unsafe { core::intrinsics::abort() }
}
#[no_mangle]
pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
unsafe { core::intrinsics::abort() }
}

View file

@ -0,0 +1,15 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![crate_type = "dylib"]
pub fn foo() {}

View file

@ -0,0 +1,12 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub fn foo() {}

View file

@ -0,0 +1,16 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![feature(allocator, no_std, core)]
#![allocator]
#![crate_type = "rlib"]
#![no_std]

View file

@ -0,0 +1,16 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![feature(allocator, no_std, core)]
#![allocator]
#![crate_type = "rlib"]
#![no_std]

View file

@ -0,0 +1,19 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![feature(no_std, allocator)]
#![no_std]
#![allocator]
#![crate_type = "rlib"]
extern crate needs_allocator;

View file

@ -0,0 +1,16 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![feature(no_std, needs_allocator)]
#![no_std]
#![needs_allocator]
#![crate_type = "rlib"]

View file

@ -0,0 +1,21 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: `allocator3` cannot depend on a crate that needs an allocator
// aux-build:needs_allocator.rs
// aux-build:allocator3.rs
// The needs_allocator crate is a dependency of the allocator crate allocator3,
// which is not allowed
extern crate allocator3;
fn main() {
}

View file

@ -0,0 +1,27 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-msvc everything is the system allocator on msvc
// aux-build:allocator-dylib.rs
// no-prefer-dynamic
// error-pattern: cannot link together two allocators
// Verify that the allocator for statically linked dynamic libraries is the
// system allocator. Do this by linking in jemalloc and making sure that we get
// an error.
#![feature(alloc_jemalloc)]
extern crate allocator_dylib;
extern crate alloc_jemalloc;
fn main() {
allocator_dylib::foo();
}

View file

@ -0,0 +1,26 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-msvc everything is the system allocator on msvc
// aux-build:allocator-dylib2.rs
// error-pattern: cannot link together two allocators
// Ensure that rust dynamic libraries use jemalloc as their allocator, verifying
// by linking in the system allocator here and ensuring that we get a complaint.
#![feature(alloc_system)]
extern crate allocator_dylib2;
extern crate alloc_system;
fn main() {
allocator_dylib2::foo();
}

View file

@ -0,0 +1,13 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allocator] //~ ERROR: experimental feature
fn main() {}

View file

@ -0,0 +1,14 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![needs_allocator] //~ ERROR the `#[needs_allocator]` attribute is
fn main() {}

View file

@ -0,0 +1,21 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: cannot link together two allocators: allocator1 and allocator2
// aux-build:allocator1.rs
// aux-build:allocator2.rs
// Make sure we can't link together two explicit allocators.
extern crate allocator1;
extern crate allocator2;
fn main() {}

View file

@ -0,0 +1,21 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:allocator1.rs
// error-pattern: cannot link together two allocators
// We're linking std dynamically (via -C prefer-dynamic for this test) which
// has an allocator and then we're also linking in a new allocator (allocator1)
// and this should be an error
extern crate allocator1;
fn main() {
}

View file

@ -0,0 +1,19 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: cannot link together two allocators
// aux-build:allocator1.rs
// aux-build:allocator2.rs
extern crate allocator1;
extern crate allocator2;
fn main() {}

View file

@ -0,0 +1,20 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(alloc_jemalloc, alloc_system)]
#[cfg(not(target_env = "msvc"))]
extern crate alloc_jemalloc;
#[cfg(target_env = "msvc")]
extern crate alloc_system;
fn main() {
println!("{:?}", Box::new(3));
}

View file

@ -0,0 +1,20 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
// ignore-msvc no jemalloc on msvc
#![feature(alloc_jemalloc)]
extern crate alloc_jemalloc;
fn main() {
println!("{:?}", Box::new(3));
}

View file

@ -0,0 +1,24 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
// aux-build:allocator-dummy.rs
extern crate allocator_dummy;
fn main() {
unsafe {
let before = allocator_dummy::HITS;
let b = Box::new(3);
assert_eq!(allocator_dummy::HITS - before, 1);
drop(b);
assert_eq!(allocator_dummy::HITS - before, 2);
}
}

View file

@ -0,0 +1,19 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![feature(alloc_system)]
extern crate alloc_system;
fn main() {
println!("{:?}", Box::new(3));
}