rustc: Allow changing the default allocator
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:
parent
e7261f3ab6
commit
45bf1ed1a1
55 changed files with 1287 additions and 647 deletions
25
mk/crates.mk
25
mk/crates.mk
|
@ -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.
|
||||
#
|
||||
|
|
6
mk/rt.mk
6
mk/rt.mk
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
96
src/liballoc_jemalloc/lib.rs
Normal file
96
src/liballoc_jemalloc/lib.rs
Normal 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
212
src/liballoc_system/lib.rs
Normal 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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
};
|
||||
|
|
|
@ -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(","));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ pub fn opts() -> TargetOptions {
|
|||
"/NXCOMPAT".to_string(),
|
||||
],
|
||||
archive_format: "gnu".to_string(),
|
||||
exe_allocation_crate: super::best_allocator(),
|
||||
|
||||
.. Default::default()
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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")),
|
||||
|
|
55
src/test/auxiliary/allocator-dummy.rs
Normal file
55
src/test/auxiliary/allocator-dummy.rs
Normal 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() }
|
||||
}
|
15
src/test/auxiliary/allocator-dylib.rs
Normal file
15
src/test/auxiliary/allocator-dylib.rs
Normal 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() {}
|
12
src/test/auxiliary/allocator-dylib2.rs
Normal file
12
src/test/auxiliary/allocator-dylib2.rs
Normal 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() {}
|
||||
|
16
src/test/auxiliary/allocator1.rs
Normal file
16
src/test/auxiliary/allocator1.rs
Normal 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]
|
16
src/test/auxiliary/allocator2.rs
Normal file
16
src/test/auxiliary/allocator2.rs
Normal 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]
|
19
src/test/auxiliary/allocator3.rs
Normal file
19
src/test/auxiliary/allocator3.rs
Normal 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;
|
||||
|
16
src/test/auxiliary/needs_allocator.rs
Normal file
16
src/test/auxiliary/needs_allocator.rs
Normal 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"]
|
|
@ -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() {
|
||||
}
|
27
src/test/compile-fail/allocator-dylib-is-system.rs
Normal file
27
src/test/compile-fail/allocator-dylib-is-system.rs
Normal 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();
|
||||
}
|
26
src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs
Normal file
26
src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs
Normal 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();
|
||||
}
|
||||
|
13
src/test/compile-fail/feature-gate-allocator.rs
Normal file
13
src/test/compile-fail/feature-gate-allocator.rs
Normal 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() {}
|
14
src/test/compile-fail/feature-gate-needs-allocator.rs
Normal file
14
src/test/compile-fail/feature-gate-needs-allocator.rs
Normal 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() {}
|
||||
|
21
src/test/compile-fail/two-allocators-2.rs
Normal file
21
src/test/compile-fail/two-allocators-2.rs
Normal 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() {}
|
||||
|
21
src/test/compile-fail/two-allocators-3.rs
Normal file
21
src/test/compile-fail/two-allocators-3.rs
Normal 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() {
|
||||
}
|
19
src/test/compile-fail/two-allocators.rs
Normal file
19
src/test/compile-fail/two-allocators.rs
Normal 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() {}
|
20
src/test/run-pass/allocator-default.rs
Normal file
20
src/test/run-pass/allocator-default.rs
Normal 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));
|
||||
}
|
20
src/test/run-pass/allocator-jemalloc.rs
Normal file
20
src/test/run-pass/allocator-jemalloc.rs
Normal 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));
|
||||
}
|
24
src/test/run-pass/allocator-override.rs
Normal file
24
src/test/run-pass/allocator-override.rs
Normal 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);
|
||||
}
|
||||
}
|
19
src/test/run-pass/allocator-system.rs
Normal file
19
src/test/run-pass/allocator-system.rs
Normal 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));
|
||||
}
|
Loading…
Add table
Reference in a new issue