Auto merge of #55660 - alexcrichton:cleanup-alloc-system, r=dtolnay,SimonSapin

Remove the `alloc_system` crate

In what's hopefully one of the final nails in the coffin of the "old allocator story of yore" this PR deletes the `alloc_system` crate and all traces of it from the compiler. The compiler no longer needs to inject allocator crates anywhere and the `alloc_system` crate has no real reason to exist outside the standard library.

The unstable `alloc_system` crate is folded directly into the standard library where its stable interface, the `System` type, remains the same. All unstable traces of `alloc_system` are removed, however.
This commit is contained in:
bors 2018-11-11 19:51:56 +00:00
commit ca79ecd694
58 changed files with 464 additions and 682 deletions

View File

@ -15,16 +15,6 @@ dependencies = [
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "alloc_system"
version = "0.0.0"
dependencies = [
"compiler_builtins 0.0.0",
"core 0.0.0",
"dlmalloc 0.0.0",
"libc 0.0.0",
]
[[package]]
name = "ammonia"
version = "1.1.0"
@ -2104,7 +2094,6 @@ name = "rustc_asan"
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
@ -2276,7 +2265,6 @@ name = "rustc_lsan"
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
@ -2328,7 +2316,6 @@ name = "rustc_msan"
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
@ -2440,7 +2427,6 @@ name = "rustc_tsan"
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
@ -2679,11 +2665,11 @@ name = "std"
version = "0.0.0"
dependencies = [
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
"dlmalloc 0.0.0",
"libc 0.0.0",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",

View File

@ -859,7 +859,6 @@ impl Step for Src {
"src/build_helper",
"src/dlmalloc",
"src/liballoc",
"src/liballoc_system",
"src/libbacktrace",
"src/libcompiler_builtins",
"src/libcore",

View File

@ -1,4 +1,4 @@
FROM ubuntu:16.04
FROM ubuntu:18.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \

View File

@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use alloc_system::System;
use std::alloc::{Global, Alloc, Layout};
use std::alloc::{Global, Alloc, Layout, System};
/// https://github.com/rust-lang/rust/issues/45955
#[test]

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![feature(allocator_api)]
#![feature(alloc_system)]
#![feature(box_syntax)]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
@ -20,7 +19,6 @@
#![feature(unboxed_closures)]
#![feature(repeat_generic_slice)]
extern crate alloc_system;
extern crate core;
extern crate rand;

View File

@ -1,19 +0,0 @@
[package]
authors = ["The Rust Project Developers"]
name = "alloc_system"
version = "0.0.0"
[lib]
name = "alloc_system"
path = "lib.rs"
test = false
doc = false
[dependencies]
core = { path = "../libcore" }
libc = { path = "../rustc/libc_shim" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
# See comments in the source for what this dependency is
[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
dlmalloc = { path = "../rustc/dlmalloc_shim" }

View File

@ -1,411 +0,0 @@
// 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_std]
#![allow(unused_attributes)]
#![unstable(feature = "alloc_system",
reason = "this library is unlikely to be stabilized in its current \
form or name",
issue = "32838")]
#![feature(allocator_api)]
#![feature(core_intrinsics)]
#![feature(nll)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![cfg_attr(
all(target_arch = "wasm32", not(target_os = "emscripten")),
feature(integer_atomics, stdsimd)
)]
#![cfg_attr(any(unix, target_os = "cloudabi", target_os = "redox"), feature(libc))]
#![rustc_alloc_kind = "lib"]
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
#[cfg(all(any(target_arch = "x86",
target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "asmjs",
target_arch = "wasm32")))]
#[allow(dead_code)]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "mips64",
target_arch = "s390x",
target_arch = "sparc64")))]
#[allow(dead_code)]
const MIN_ALIGN: usize = 16;
use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout};
use core::ptr::NonNull;
/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type can be used in a `static` item
/// with the `#[global_allocator]` attribute
/// to force the global allocator to be the systems one.
/// (The default is jemalloc for executables, on some platforms.)
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
/// let a = Box::new(4); // Allocates from the system allocator.
/// println!("{}", a);
/// }
/// ```
///
/// It can also be used directly to allocate memory
/// independently of the standard librarys global allocator.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
pub struct System;
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for System {
#[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
}
#[inline]
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
}
#[inline]
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
}
#[inline]
unsafe fn realloc(&mut self,
ptr: NonNull<u8>,
layout: Layout,
new_size: usize) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
}
}
#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
mod realloc_fallback {
use core::alloc::{GlobalAlloc, Layout};
use core::cmp;
use core::ptr;
impl super::System {
pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
new_size: usize) -> *mut u8 {
// Docs for GlobalAlloc::realloc require this to be valid:
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
let new_ptr = GlobalAlloc::alloc(self, new_layout);
if !new_ptr.is_null() {
let size = cmp::min(old_layout.size(), new_size);
ptr::copy_nonoverlapping(ptr, new_ptr, size);
GlobalAlloc::dealloc(self, ptr, old_layout);
}
new_ptr
}
}
}
#[cfg(any(unix, target_os = "cloudabi", target_os = "redox"))]
mod platform {
extern crate libc;
use core::ptr;
use MIN_ALIGN;
use System;
use core::alloc::{GlobalAlloc, Layout};
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::malloc(layout.size()) as *mut u8
} else {
#[cfg(target_os = "macos")]
{
if layout.align() > (1 << 31) {
return ptr::null_mut()
}
}
aligned_malloc(&layout)
}
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::calloc(layout.size(), 1) as *mut u8
} else {
let ptr = self.alloc(layout.clone());
if !ptr.is_null() {
ptr::write_bytes(ptr, 0, layout.size());
}
ptr
}
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
libc::free(ptr as *mut libc::c_void)
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
} else {
self.realloc_fallback(ptr, layout, new_size)
}
}
}
#[cfg(any(target_os = "android",
target_os = "hermit",
target_os = "redox",
target_os = "solaris"))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
// On android we currently target API level 9 which unfortunately
// doesn't have the `posix_memalign` API used below. Instead we use
// `memalign`, but this unfortunately has the property on some systems
// where the memory returned cannot be deallocated by `free`!
//
// Upon closer inspection, however, this appears to work just fine with
// Android, so for this platform we should be fine to call `memalign`
// (which is present in API level 9). Some helpful references could
// possibly be chromium using memalign [1], attempts at documenting that
// memalign + free is ok [2] [3], or the current source of chromium
// which still uses memalign on android [4].
//
// [1]: https://codereview.chromium.org/10796020/
// [2]: https://code.google.com/p/android/issues/detail?id=35391
// [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
// [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
// /memory/aligned_memory.cc
libc::memalign(layout.align(), layout.size()) as *mut u8
}
#[cfg(not(any(target_os = "android",
target_os = "hermit",
target_os = "redox",
target_os = "solaris")))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
let mut out = ptr::null_mut();
let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
if ret != 0 {
ptr::null_mut()
} else {
out as *mut u8
}
}
}
#[cfg(windows)]
#[allow(nonstandard_style)]
mod platform {
use MIN_ALIGN;
use System;
use core::alloc::{GlobalAlloc, Layout};
type LPVOID = *mut u8;
type HANDLE = LPVOID;
type SIZE_T = usize;
type DWORD = u32;
type BOOL = i32;
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;
fn GetLastError() -> DWORD;
}
#[repr(C)]
struct Header(*mut u8);
const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
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.add(align - (ptr as usize & (align - 1)));
*get_header(aligned) = Header(ptr);
aligned
}
#[inline]
unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
let ptr = if layout.align() <= MIN_ALIGN {
HeapAlloc(GetProcessHeap(), flags, layout.size())
} else {
let size = layout.size() + layout.align();
let ptr = HeapAlloc(GetProcessHeap(), flags, size);
if ptr.is_null() {
ptr
} else {
align_ptr(ptr, layout.align())
}
};
ptr as *mut u8
}
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
allocate_with_flags(layout, 0)
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
allocate_with_flags(layout, HEAP_ZERO_MEMORY)
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if layout.align() <= MIN_ALIGN {
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}",
GetLastError());
} else {
let header = get_header(ptr);
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}",
GetLastError());
}
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN {
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
} else {
self.realloc_fallback(ptr, layout, new_size)
}
}
}
}
// This is an implementation of a global allocator on the wasm32 platform when
// emscripten is not in use. In that situation there's no actual runtime for us
// to lean on for allocation, so instead we provide our own!
//
// The wasm32 instruction set has two instructions for getting the current
// amount of memory and growing the amount of memory. These instructions are the
// foundation on which we're able to build an allocator, so we do so! Note that
// the instructions are also pretty "global" and this is the "global" allocator
// after all!
//
// The current allocator here is the `dlmalloc` crate which we've got included
// in the rust-lang/rust repository as a submodule. The crate is a port of
// dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
// for now which is currently technically required (can't link with C yet).
//
// The crate itself provides a global allocator which on wasm has no
// synchronization as there are no threads!
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
mod platform {
extern crate dlmalloc;
use core::alloc::{GlobalAlloc, Layout};
use System;
static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let _lock = lock::lock();
DLMALLOC.malloc(layout.size(), layout.align())
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let _lock = lock::lock();
DLMALLOC.calloc(layout.size(), layout.align())
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let _lock = lock::lock();
DLMALLOC.free(ptr, layout.size(), layout.align())
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let _lock = lock::lock();
DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
}
}
#[cfg(target_feature = "atomics")]
mod lock {
use core::arch::wasm32;
use core::sync::atomic::{AtomicI32, Ordering::SeqCst};
static LOCKED: AtomicI32 = AtomicI32::new(0);
pub struct DropLock;
pub fn lock() -> DropLock {
loop {
if LOCKED.swap(1, SeqCst) == 0 {
return DropLock
}
unsafe {
let r = wasm32::atomic::wait_i32(
&LOCKED as *const AtomicI32 as *mut i32,
1, // expected value
-1, // timeout
);
debug_assert!(r == 0 || r == 1);
}
}
}
impl Drop for DropLock {
fn drop(&mut self) {
let r = LOCKED.swap(0, SeqCst);
debug_assert_eq!(r, 1);
unsafe {
wasm32::atomic::wake(
&LOCKED as *const AtomicI32 as *mut i32,
1, // only one thread
);
}
}
}
}
#[cfg(not(target_feature = "atomics"))]
mod lock {
#[inline]
pub fn lock() {} // no atomics, no threads, that's easy!
}
}

View File

@ -63,7 +63,6 @@
use hir::def_id::CrateNum;
use session;
use session::config;
use ty::TyCtxt;
use middle::cstore::{self, DepKind};
@ -224,7 +223,6 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// quite yet, so do so here.
activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret,
&|cnum| tcx.is_panic_runtime(cnum));
activate_injected_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
@ -303,7 +301,6 @@ fn attempt_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<DependencyLis
// that here and activate them.
activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret,
&|cnum| tcx.is_panic_runtime(cnum));
activate_injected_allocator(sess, &mut ret);
Some(ret)
}
@ -336,18 +333,6 @@ fn activate_injected_dep(injected: Option<CrateNum>,
}
}
fn activate_injected_allocator(sess: &session::Session,
list: &mut DependencyList) {
let cnum = match sess.injected_allocator.get() {
Some(cnum) => cnum,
None => return,
};
let idx = cnum.as_usize() - 1;
if 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<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) {

View File

@ -112,7 +112,6 @@ pub struct Session {
/// The metadata::creader module may inject an allocator/panic_runtime
/// dependency if it didn't already find one, and this tracks what was
/// injected.
pub injected_allocator: Once<Option<CrateNum>>,
pub allocator_kind: Once<Option<AllocatorKind>>,
pub injected_panic_runtime: Once<Option<CrateNum>>,
@ -1162,7 +1161,6 @@ pub fn build_session_(
type_length_limit: Once::new(),
const_eval_stack_frame_limit: 100,
next_node_id: OneThread::new(Cell::new(NodeId::new(1))),
injected_allocator: Once::new(),
allocator_kind: Once::new(),
injected_panic_runtime: Once::new(),
imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),

View File

@ -15,6 +15,5 @@ cmake = "0.1.18"
[dependencies]
alloc = { path = "../liballoc" }
alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![sanitizer_runtime]
#![feature(alloc_system)]
#![feature(nll)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
@ -17,10 +16,3 @@
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
extern crate alloc_system;
use alloc_system::System;
#[global_allocator]
static ALLOC: System = System;

View File

@ -15,6 +15,5 @@ cmake = "0.1.18"
[dependencies]
alloc = { path = "../liballoc" }
alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![sanitizer_runtime]
#![feature(alloc_system)]
#![feature(nll)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
@ -17,10 +16,3 @@
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
extern crate alloc_system;
use alloc_system::System;
#[global_allocator]
static ALLOC: System = System;

View File

@ -16,7 +16,7 @@ use decoder::proc_macro_def_path_table;
use schema::CrateRoot;
use rustc_data_structures::sync::{Lrc, RwLock, Lock};
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX};
use rustc::hir::def_id::CrateNum;
use rustc_data_structures::svh::Svh;
use rustc::middle::allocator::AllocatorKind;
use rustc::middle::cstore::DepKind;
@ -864,7 +864,6 @@ impl<'a> CrateLoader<'a> {
needs_allocator = needs_allocator || data.root.needs_allocator;
});
if !needs_allocator {
self.sess.injected_allocator.set(None);
self.sess.allocator_kind.set(None);
return
}
@ -872,20 +871,15 @@ impl<'a> CrateLoader<'a> {
// At this point we've determined that we need an allocator. Let's see
// if our compilation session actually needs an allocator based on what
// we're emitting.
let mut need_lib_alloc = false;
let mut need_exe_alloc = false;
for ct in self.sess.crate_types.borrow().iter() {
match *ct {
config::CrateType::Executable => need_exe_alloc = true,
config::CrateType::Dylib |
config::CrateType::ProcMacro |
config::CrateType::Cdylib |
config::CrateType::Staticlib => need_lib_alloc = true,
config::CrateType::Rlib => {}
}
}
if !need_lib_alloc && !need_exe_alloc {
self.sess.injected_allocator.set(None);
let all_rlib = self.sess.crate_types.borrow()
.iter()
.all(|ct| {
match *ct {
config::CrateType::Rlib => true,
_ => false,
}
});
if all_rlib {
self.sess.allocator_kind.set(None);
return
}
@ -924,103 +918,27 @@ impl<'a> CrateLoader<'a> {
});
if global_allocator.is_some() {
self.sess.allocator_kind.set(Some(AllocatorKind::Global));
self.sess.injected_allocator.set(None);
return
}
// Ok we haven't found a global allocator but we still need an
// allocator. At this point we'll either fall back to the "library
// allocator" or the "exe allocator" depending on a few variables. Let's
// figure out which one.
//
// Note that here we favor linking to the "library allocator" as much as
// possible. If we're not creating rustc's version of libstd
// (need_lib_alloc and prefer_dynamic) then we select `None`, and if the
// exe allocation crate doesn't exist for this target then we also
// select `None`.
let exe_allocation_crate_data =
if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
None
} else {
self.sess
.target
.target
.options
.exe_allocation_crate
.as_ref()
.map(|name| {
// We've determined that we're injecting an "exe allocator" which means
// that we're going to load up a whole new crate. An example of this is
// that we're producing a normal binary on Linux which means we need to
// load the `alloc_jemalloc` crate to link as an allocator.
let name = Symbol::intern(name);
let (cnum, data) = self.resolve_crate(&None,
name,
name,
None,
None,
DUMMY_SP,
PathKind::Crate,
DepKind::Implicit)
.unwrap_or_else(|err| err.report());
self.sess.injected_allocator.set(Some(cnum));
data
})
};
let allocation_crate_data = exe_allocation_crate_data.or_else(|| {
// No allocator was injected
self.sess.injected_allocator.set(None);
if attr::contains_name(&krate.attrs, "default_lib_allocator") {
// Prefer self as the allocator if there's a collision
return None;
// allocator. At this point our allocator request is typically fulfilled
// by the standard library, denoted by the `#![default_lib_allocator]`
// attribute.
let mut has_default = attr::contains_name(&krate.attrs, "default_lib_allocator");
self.cstore.iter_crate_data(|_, data| {
if data.root.has_default_lib_allocator {
has_default = true;
}
// We're not actually going to inject an allocator, we're going to
// require that something in our crate graph is the default lib
// allocator. This is typically libstd, so this'll rarely be an
// error.
let mut allocator = None;
self.cstore.iter_crate_data(|_, data| {
if allocator.is_none() && data.root.has_default_lib_allocator {
allocator = Some(data.clone());
}
});
allocator
});
match allocation_crate_data {
Some(data) => {
// We have an allocator. We detect separately what kind it is, to allow for some
// flexibility in misconfiguration.
let attrs = data.get_item_attrs(CRATE_DEF_INDEX, self.sess);
let kind_interned = attr::first_attr_value_str_by_name(&attrs, "rustc_alloc_kind")
.map(Symbol::as_str);
let kind_str = kind_interned
.as_ref()
.map(|s| s as &str);
let alloc_kind = match kind_str {
None |
Some("lib") => AllocatorKind::DefaultLib,
Some("exe") => AllocatorKind::DefaultExe,
Some(other) => {
self.sess.err(&format!("Allocator kind {} not known", other));
return;
}
};
self.sess.allocator_kind.set(Some(alloc_kind));
},
None => {
if !attr::contains_name(&krate.attrs, "default_lib_allocator") {
self.sess.err("no global memory allocator found but one is \
required; link to std or \
add #[global_allocator] to a static item \
that implements the GlobalAlloc trait.");
return;
}
self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib));
}
if !has_default {
self.sess.err("no global memory allocator found but one is \
required; link to std or \
add #[global_allocator] to a static item \
that implements the GlobalAlloc trait.");
}
self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib));
fn has_global_allocator(krate: &ast::Crate) -> bool {
struct Finder(bool);
@ -1083,8 +1001,6 @@ impl<'a> CrateLoader<'a> {
impl<'a> CrateLoader<'a> {
pub fn postprocess(&mut self, krate: &ast::Crate) {
// inject the sanitizer runtime before the allocator runtime because all
// sanitizers force the use of the `alloc_system` allocator
self.inject_sanitizer_runtime();
self.inject_profiler_runtime();
self.inject_allocator_crate(krate);

View File

@ -15,6 +15,5 @@ cmake = "0.1.18"
[dependencies]
alloc = { path = "../liballoc" }
alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![sanitizer_runtime]
#![feature(alloc_system)]
#![feature(nll)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
@ -17,10 +16,3 @@
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
extern crate alloc_system;
use alloc_system::System;
#[global_allocator]
static ALLOC: System = System;

View File

@ -14,9 +14,6 @@ pub fn target() -> TargetResult {
let mut base = super::freebsd_base::opts();
base.max_atomic_width = Some(128);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "aarch64-unknown-freebsd".to_string(),
target_endian: "little".to_string(),

View File

@ -14,9 +14,6 @@ pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.max_atomic_width = Some(128);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "aarch64-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),

View File

@ -14,9 +14,6 @@ pub fn target() -> TargetResult {
let mut base = super::linux_musl_base::opts();
base.max_atomic_width = Some(128);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "aarch64-unknown-linux-musl".to_string(),
target_endian: "little".to_string(),

View File

@ -21,7 +21,6 @@ pub fn opts() -> TargetOptions {
]);
TargetOptions {
exe_allocation_crate: None,
executables: true,
has_elf_tls: true,
linker_is_gnu: true,

View File

@ -30,7 +30,6 @@ pub fn opts() -> TargetOptions {
TargetOptions {
executables: true,
has_elf_tls: false,
exe_allocation_crate: None,
panic_strategy: PanicStrategy::Abort,
linker: Some("ld".to_string()),
pre_link_args: args,

View File

@ -28,9 +28,6 @@ pub fn target() -> TargetResult {
features: "+mips64r2".to_string(),
max_atomic_width: Some(64),
// see #36994
exe_allocation_crate: None,
..super::linux_base::opts()
},
})

View File

@ -28,9 +28,6 @@ pub fn target() -> TargetResult {
features: "+mips64r2".to_string(),
max_atomic_width: Some(64),
// see #36994
exe_allocation_crate: None,
..super::linux_base::opts()
},
})

View File

@ -27,9 +27,6 @@ pub fn target() -> TargetResult {
features: "+mips32r2,+fpxx,+nooddspreg".to_string(),
max_atomic_width: Some(32),
// see #36994
exe_allocation_crate: None,
..super::linux_base::opts()
},
})

View File

@ -15,8 +15,6 @@ pub fn target() -> TargetResult {
base.cpu = "mips32r2".to_string();
base.features = "+mips32r2,+soft-float".to_string();
base.max_atomic_width = Some(32);
// see #36994
base.exe_allocation_crate = None;
base.crt_static_default = false;
Ok(Target {
llvm_target: "mips-unknown-linux-musl".to_string(),

View File

@ -27,9 +27,6 @@ pub fn target() -> TargetResult {
features: "+mips32r2,+soft-float".to_string(),
max_atomic_width: Some(32),
// see #36994
exe_allocation_crate: None,
..super::linux_base::opts()
},
})

View File

@ -28,9 +28,6 @@ pub fn target() -> TargetResult {
features: "+mips32r2,+fpxx,+nooddspreg".to_string(),
max_atomic_width: Some(32),
// see #36994
exe_allocation_crate: None,
..super::linux_base::opts()
},
})

View File

@ -15,8 +15,6 @@ pub fn target() -> TargetResult {
base.cpu = "mips32r2".to_string();
base.features = "+mips32r2,+soft-float".to_string();
base.max_atomic_width = Some(32);
// see #36994
base.exe_allocation_crate = None;
base.crt_static_default = false;
Ok(Target {
llvm_target: "mipsel-unknown-linux-musl".to_string(),

View File

@ -28,9 +28,6 @@ pub fn target() -> TargetResult {
features: "+mips32r2,+soft-float".to_string(),
max_atomic_width: Some(32),
// see #36994
exe_allocation_crate: None,
..super::linux_base::opts()
},
})

View File

@ -596,9 +596,6 @@ pub struct TargetOptions {
/// `eh_unwind_resume` lang item.
pub custom_unwind_resume: bool,
/// If necessary, a different crate to link exe allocators by default
pub exe_allocation_crate: Option<String>,
/// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for
/// this target.
pub has_elf_tls: bool,
@ -740,7 +737,6 @@ impl Default for TargetOptions {
link_env: Vec::new(),
archive_format: "gnu".to_string(),
custom_unwind_resume: false,
exe_allocation_crate: None,
allow_asm: true,
has_elf_tls: false,
obj_is_bitcode: false,
@ -1025,7 +1021,6 @@ impl Target {
key!(archive_format);
key!(allow_asm, bool);
key!(custom_unwind_resume, bool);
key!(exe_allocation_crate, optional);
key!(has_elf_tls, bool);
key!(obj_is_bitcode, bool);
key!(no_integrated_as, bool);
@ -1235,7 +1230,6 @@ impl ToJson for Target {
target_option_val!(archive_format);
target_option_val!(allow_asm);
target_option_val!(custom_unwind_resume);
target_option_val!(exe_allocation_crate);
target_option_val!(has_elf_tls);
target_option_val!(obj_is_bitcode);
target_option_val!(no_integrated_as);

View File

@ -20,9 +20,6 @@ pub fn target() -> TargetResult {
// for now. https://github.com/rust-lang/rust/pull/43170#issuecomment-315411474
base.relro_level = RelroLevel::Partial;
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
target_endian: "big".to_string(),

View File

@ -16,9 +16,6 @@ pub fn target() -> TargetResult {
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),

View File

@ -16,9 +16,6 @@ pub fn target() -> TargetResult {
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "powerpc64le-unknown-linux-musl".to_string(),
target_endian: "little".to_string(),

View File

@ -15,9 +15,6 @@ pub fn target() -> TargetResult {
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.max_atomic_width = Some(32);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "powerpc-unknown-linux-gnu".to_string(),
target_endian: "big".to_string(),

View File

@ -15,9 +15,6 @@ pub fn target() -> TargetResult {
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
base.max_atomic_width = Some(32);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
target_endian: "big".to_string(),

View File

@ -15,9 +15,6 @@ pub fn target() -> TargetResult {
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.max_atomic_width = Some(32);
// see #36994
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "powerpc-unknown-netbsd".to_string(),
target_endian: "big".to_string(),

View File

@ -19,8 +19,6 @@ pub fn target() -> TargetResult {
// Pass the -vector feature string to LLVM to respect this assumption.
base.features = "-vector".to_string();
base.max_atomic_width = Some(64);
// see #36994
base.exe_allocation_crate = None;
base.min_global_align = Some(16);
Ok(Target {

View File

@ -14,7 +14,6 @@ pub fn target() -> TargetResult {
let mut base = super::linux_base::opts();
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "sparc64-unknown-linux-gnu".to_string(),

View File

@ -15,7 +15,6 @@ pub fn target() -> TargetResult {
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "sparc-unknown-linux-gnu".to_string(),

View File

@ -16,7 +16,6 @@ pub fn target() -> TargetResult {
// llvm calls this "v9"
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
base.exe_allocation_crate = None;
Ok(Target {
llvm_target: "sparcv9-sun-solaris".to_string(),

View File

@ -21,7 +21,6 @@ pub fn target() -> TargetResult {
base.has_rpath = false;
base.position_independent_executables = false;
base.disable_redzone = true;
base.exe_allocation_crate = None;
base.stack_probes = true;
Ok(Target {

View File

@ -15,6 +15,5 @@ cmake = "0.1.18"
[dependencies]
alloc = { path = "../liballoc" }
alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }

View File

@ -9,7 +9,6 @@
// except according to those terms.
#![sanitizer_runtime]
#![feature(alloc_system)]
#![feature(nll)]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
@ -17,10 +16,3 @@
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
extern crate alloc_system;
use alloc_system::System;
#[global_allocator]
static ALLOC: System = System;

View File

@ -14,7 +14,6 @@ crate-type = ["dylib", "rlib"]
[dependencies]
alloc = { path = "../liballoc" }
alloc_system = { path = "../liballoc_system" }
panic_unwind = { path = "../libpanic_unwind", optional = true }
panic_abort = { path = "../libpanic_abort" }
core = { path = "../libcore" }
@ -36,6 +35,9 @@ rustc_lsan = { path = "../librustc_lsan" }
rustc_msan = { path = "../librustc_msan" }
rustc_tsan = { path = "../librustc_tsan" }
[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
dlmalloc = { path = '../rustc/dlmalloc_shim' }
[build-dependencies]
cc = "1.0"
build_helper = { path = "../build_helper" }

View File

@ -73,15 +73,100 @@
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};
use core::ptr::NonNull;
use sys_common::util::dumb_print;
#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;
/// The default memory allocator provided by the operating system.
///
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by deafult
/// work as if they had this definition:
///
/// ```rust
/// use std::alloc::System;
///
/// #[global_allocator]
/// static A: System = System;
///
/// fn main() {
/// let a = Box::new(4); // Allocates from the system allocator.
/// println!("{}", a);
/// }
/// ```
///
/// You can also define your own wrapper around `System` if you'd like, such as
/// keeping track of the number of all bytes allocated:
///
/// ```rust
/// use std::alloc::{System, GlobalAlloc, Layout};
/// use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering::SeqCst};
///
/// struct Counter;
///
/// static ALLOCATED: AtomicUsize = ATOMIC_USIZE_INIT;
///
/// unsafe impl GlobalAlloc for Counter {
/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
/// let ret = System.alloc(layout);
/// if !ret.is_null() {
/// ALLOCATED.fetch_add(layout.size(), SeqCst);
/// }
/// return ret
/// }
///
/// unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
/// System.dealloc(ptr, layout);
/// ALLOCATED.fetch_sub(layout.size(), SeqCst);
/// }
/// }
///
/// #[global_allocator]
/// static A: Counter = Counter;
///
/// fn main() {
/// println!("allocated bytes before main: {}", ALLOCATED.load(SeqCst));
/// }
/// ```
///
/// It can also be used directly to allocate memory independently of whatever
/// global allocator has been selected for a Rust program. For example if a Rust
/// program opts in to using jemalloc as the global allocator, `System` will
/// still allocate memory using `malloc` and `HeapAlloc`.
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[doc(inline)]
pub use alloc_system::System;
#[derive(Debug, Copy, Clone)]
pub struct System;
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for System {
#[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
}
#[inline]
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
}
#[inline]
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
}
#[inline]
unsafe fn realloc(&mut self,
ptr: NonNull<u8>,
layout: Layout,
new_size: usize) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
}
}
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

View File

@ -235,7 +235,6 @@
#![cfg_attr(test, feature(test, update_panic_count))]
#![feature(alloc)]
#![feature(alloc_error_handler)]
#![feature(alloc_system)]
#![feature(allocator_api)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
@ -316,7 +315,7 @@
#[cfg(stage0)]
#[global_allocator]
static ALLOC: alloc_system::System = alloc_system::System;
static ALLOC: alloc::System = alloc::System;
// Explicitly import the prelude. The compiler uses this same unstable attribute
// to import the prelude implicitly when building crates that depend on std.
@ -337,7 +336,6 @@ pub use core::{unreachable, unimplemented, write, writeln, try};
#[allow(unused_imports)] // macros from `alloc` are not used on all platforms
#[macro_use]
extern crate alloc as alloc_crate;
extern crate alloc_system;
#[doc(masked)]
extern crate libc;

View File

@ -12,6 +12,8 @@ use io;
use libc;
use mem;
#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;

View File

@ -15,6 +15,8 @@ use io::{self, ErrorKind};
pub use libc::strlen;
pub use self::rand::hashmap_random_keys;
#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;

View File

@ -0,0 +1,100 @@
// Copyright 2018 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.
use ptr;
use libc;
use sys_common::alloc::{MIN_ALIGN, realloc_fallback};
use alloc::{GlobalAlloc, Layout, System};
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::malloc(layout.size()) as *mut u8
} else {
#[cfg(target_os = "macos")]
{
if layout.align() > (1 << 31) {
return ptr::null_mut()
}
}
aligned_malloc(&layout)
}
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::calloc(layout.size(), 1) as *mut u8
} else {
let ptr = self.alloc(layout.clone());
if !ptr.is_null() {
ptr::write_bytes(ptr, 0, layout.size());
}
ptr
}
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
libc::free(ptr as *mut libc::c_void)
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
} else {
realloc_fallback(self, ptr, layout, new_size)
}
}
}
#[cfg(any(target_os = "android",
target_os = "hermit",
target_os = "redox",
target_os = "solaris"))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
// On android we currently target API level 9 which unfortunately
// doesn't have the `posix_memalign` API used below. Instead we use
// `memalign`, but this unfortunately has the property on some systems
// where the memory returned cannot be deallocated by `free`!
//
// Upon closer inspection, however, this appears to work just fine with
// Android, so for this platform we should be fine to call `memalign`
// (which is present in API level 9). Some helpful references could
// possibly be chromium using memalign [1], attempts at documenting that
// memalign + free is ok [2] [3], or the current source of chromium
// which still uses memalign on android [4].
//
// [1]: https://codereview.chromium.org/10796020/
// [2]: https://code.google.com/p/android/issues/detail?id=35391
// [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
// [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
// /memory/aligned_memory.cc
libc::memalign(layout.align(), layout.size()) as *mut u8
}
#[cfg(not(any(target_os = "android",
target_os = "hermit",
target_os = "redox",
target_os = "solaris")))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
let mut out = ptr::null_mut();
let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
if ret != 0 {
ptr::null_mut()
} else {
out as *mut u8
}
}

View File

@ -36,6 +36,7 @@ pub use libc::strlen;
#[macro_use]
pub mod weak;
pub mod alloc;
pub mod args;
pub mod android;
#[cfg(feature = "backtrace")]

View File

@ -0,0 +1,105 @@
// Copyright 2018 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.
//! This is an implementation of a global allocator on the wasm32 platform when
//! emscripten is not in use. In that situation there's no actual runtime for us
//! to lean on for allocation, so instead we provide our own!
//!
//! The wasm32 instruction set has two instructions for getting the current
//! amount of memory and growing the amount of memory. These instructions are the
//! foundation on which we're able to build an allocator, so we do so! Note that
//! the instructions are also pretty "global" and this is the "global" allocator
//! after all!
//!
//! The current allocator here is the `dlmalloc` crate which we've got included
//! in the rust-lang/rust repository as a submodule. The crate is a port of
//! dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
//! for now which is currently technically required (can't link with C yet).
//!
//! The crate itself provides a global allocator which on wasm has no
//! synchronization as there are no threads!
extern crate dlmalloc;
use alloc::{GlobalAlloc, Layout, System};
static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let _lock = lock::lock();
DLMALLOC.malloc(layout.size(), layout.align())
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let _lock = lock::lock();
DLMALLOC.calloc(layout.size(), layout.align())
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let _lock = lock::lock();
DLMALLOC.free(ptr, layout.size(), layout.align())
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let _lock = lock::lock();
DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
}
}
#[cfg(target_feature = "atomics")]
mod lock {
use arch::wasm32;
use sync::atomic::{AtomicI32, Ordering::SeqCst};
static LOCKED: AtomicI32 = AtomicI32::new(0);
pub struct DropLock;
pub fn lock() -> DropLock {
loop {
if LOCKED.swap(1, SeqCst) == 0 {
return DropLock
}
unsafe {
let r = wasm32::atomic::wait_i32(
&LOCKED as *const AtomicI32 as *mut i32,
1, // expected value
-1, // timeout
);
debug_assert!(r == 0 || r == 1);
}
}
}
impl Drop for DropLock {
fn drop(&mut self) {
let r = LOCKED.swap(0, SeqCst);
debug_assert_eq!(r, 1);
unsafe {
wasm32::atomic::wake(
&LOCKED as *const AtomicI32 as *mut i32,
1, // only one thread
);
}
}
}
}
#[cfg(not(target_feature = "atomics"))]
mod lock {
#[inline]
pub fn lock() {} // no atomics, no threads, that's easy!
}

View File

@ -32,6 +32,7 @@ use sys_common::{AsInner, FromInner};
use ffi::{OsString, OsStr};
use time::Duration;
pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;

View File

@ -0,0 +1,77 @@
// Copyright 2018 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.
use alloc::{GlobalAlloc, Layout, System};
use sys::c;
use sys_common::alloc::{MIN_ALIGN, realloc_fallback};
#[repr(C)]
struct Header(*mut u8);
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.add(align - (ptr as usize & (align - 1)));
*get_header(aligned) = Header(ptr);
aligned
}
#[inline]
unsafe fn allocate_with_flags(layout: Layout, flags: c::DWORD) -> *mut u8 {
if layout.align() <= MIN_ALIGN {
return c::HeapAlloc(c::GetProcessHeap(), flags, layout.size()) as *mut u8
}
let size = layout.size() + layout.align();
let ptr = c::HeapAlloc(c::GetProcessHeap(), flags, size);
if ptr.is_null() {
ptr as *mut u8
} else {
align_ptr(ptr as *mut u8, layout.align())
}
}
#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
allocate_with_flags(layout, 0)
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
allocate_with_flags(layout, c::HEAP_ZERO_MEMORY)
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if layout.align() <= MIN_ALIGN {
let err = c::HeapFree(c::GetProcessHeap(), 0, ptr as c::LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}",
c::GetLastError());
} else {
let header = get_header(ptr);
let err = c::HeapFree(c::GetProcessHeap(), 0, header.0 as c::LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}",
c::GetLastError());
}
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN {
c::HeapReAlloc(c::GetProcessHeap(), 0, ptr as c::LPVOID, new_size) as *mut u8
} else {
realloc_fallback(self, ptr, layout, new_size)
}
}
}

View File

@ -309,6 +309,8 @@ pub const FD_SETSIZE: usize = 64;
pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
#[repr(C)]
#[cfg(not(target_pointer_width = "64"))]
pub struct WSADATA {
@ -1277,6 +1279,11 @@ extern "system" {
#[link_name = "SystemFunction036"]
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
pub fn GetProcessHeap() -> HANDLE;
pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
}
// Functions that aren't available on every version of Windows that we support,

View File

@ -22,6 +22,7 @@ pub use self::rand::hashmap_random_keys;
#[macro_use] pub mod compat;
pub mod alloc;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;

View File

@ -0,0 +1,50 @@
// Copyright 2018 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.
#![allow(dead_code)]
use alloc::{GlobalAlloc, Layout, System};
use cmp;
use ptr;
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values.
#[cfg(all(any(target_arch = "x86",
target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "asmjs",
target_arch = "wasm32")))]
pub const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "mips64",
target_arch = "s390x",
target_arch = "sparc64")))]
pub const MIN_ALIGN: usize = 16;
pub unsafe fn realloc_fallback(
alloc: &System,
ptr: *mut u8,
old_layout: Layout,
new_size: usize,
) -> *mut u8 {
// Docs for GlobalAlloc::realloc require this to be valid:
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
let new_ptr = GlobalAlloc::alloc(alloc, new_layout);
if !new_ptr.is_null() {
let size = cmp::min(old_layout.size(), new_size);
ptr::copy_nonoverlapping(ptr, new_ptr, size);
GlobalAlloc::dealloc(alloc, ptr, old_layout);
}
new_ptr
}

View File

@ -38,6 +38,7 @@ macro_rules! rtassert {
})
}
pub mod alloc;
pub mod at_exit_imp;
#[cfg(feature = "backtrace")]
pub mod backtrace;

View File

@ -27,7 +27,6 @@
//!
//! - core may not have platform-specific code
//! - libcompiler_builtins may have platform-specific code
//! - liballoc_system may have platform-specific code
//! - libpanic_abort may have platform-specific code
//! - libpanic_unwind may have platform-specific code
//! - libunwind may have platform-specific code
@ -51,7 +50,6 @@ use std::iter::Iterator;
// Paths that may contain platform-specific code
const EXCEPTION_PATHS: &[&str] = &[
// std crates
"src/liballoc_system",
"src/libcompiler_builtins",
"src/liblibc",
"src/libpanic_abort",