Auto merge of #51241 - glandium:globalalloc, r=sfackler,SimonSapin

Stabilize GlobalAlloc and #[global_allocator]

This PR implements the changes discussed in https://github.com/rust-lang/rust/issues/49668#issuecomment-393263510

Fixes #49668
Fixes #27389

This does not change the default global allocator: #36963
This commit is contained in:
bors 2018-06-12 00:36:21 +00:00
commit 4367e41ea2
46 changed files with 569 additions and 632 deletions

View File

@ -1,72 +0,0 @@
# `global_allocator`
The tracking issue for this feature is: [#27389]
[#27389]: https://github.com/rust-lang/rust/issues/27389
------------------------
Rust programs may need to change the allocator that they're running with from
time to time. This use case is distinct from an allocator-per-collection (e.g. a
`Vec` with a custom allocator) and instead is more related to changing the
global default allocator, e.g. what `Vec<T>` uses by default.
Currently Rust programs don't have a specified global allocator. The compiler
may link to a version of [jemalloc] on some platforms, but this is not
guaranteed. Libraries, however, like cdylibs and staticlibs are guaranteed
to use the "system allocator" which means something like `malloc` on Unixes and
`HeapAlloc` on Windows.
[jemalloc]: https://github.com/jemalloc/jemalloc
The `#[global_allocator]` attribute, however, allows configuring this choice.
You can use this to implement a completely custom global allocator to route all
default allocation requests to a custom object. Defined in [RFC 1974] usage
looks like:
[RFC 1974]: https://github.com/rust-lang/rfcs/pull/1974
```rust
#![feature(global_allocator, allocator_api, heap_api)]
use std::alloc::{GlobalAlloc, System, Layout, Opaque};
use std::ptr::NonNull;
struct MyAllocator;
unsafe impl GlobalAlloc for MyAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
System.alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
System.dealloc(ptr, layout)
}
}
#[global_allocator]
static GLOBAL: MyAllocator = MyAllocator;
fn main() {
// This `Vec` will allocate memory through `GLOBAL` above
let mut v = Vec::new();
v.push(1);
}
```
And that's it! The `#[global_allocator]` attribute is applied to a `static`
which implements the `Alloc` trait in the `std::alloc` module. Note, though,
that the implementation is defined for `&MyAllocator`, not just `MyAllocator`.
You may wish, however, to also provide `Alloc for MyAllocator` for other use
cases.
A crate can only have one instance of `#[global_allocator]` and this instance
may be loaded through a dependency. For example `#[global_allocator]` above
could have been placed in one of the dependencies loaded through `extern crate`.
Note that `Alloc` itself is an `unsafe` trait, with much documentation on the
trait itself about usage and for implementors. Extra care should be taken when
implementing a global allocator as well as the allocator may be called from many
portions of the standard library, such as the panicking routine. As a result it
is highly recommended to not panic during allocation and work in as many
situations with as few dependencies as possible as well.

View File

@ -1,13 +0,0 @@
# `alloc_jemalloc`
The tracking issue for this feature is: [#33082]
[#33082]: https://github.com/rust-lang/rust/issues/33082
See also [`alloc_system`](library-features/alloc-system.html).
------------------------
This feature has been replaced by [the `jemallocator` crate on crates.io.][jemallocator].
[jemallocator]: https://crates.io/crates/jemallocator

View File

@ -1,77 +0,0 @@
# `alloc_system`
The tracking issue for this feature is: [#32838]
[#32838]: https://github.com/rust-lang/rust/issues/32838
See also [`global_allocator`](language-features/global-allocator.html).
------------------------
The compiler currently ships two default allocators: `alloc_system` and
`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
are normal Rust crates and contain an implementation of the routines to
allocate and deallocate memory. The standard library is not compiled assuming
either one, and the compiler will decide which allocator is in use at
compile-time depending on the type of output artifact being produced.
Binaries generated by the compiler will use `alloc_jemalloc` by default (where
available). In this situation the compiler "controls the world" in the sense of
it has power over the final link. Primarily this means that the allocator
decision can be left up the compiler.
Dynamic and static libraries, however, will use `alloc_system` by default. Here
Rust is typically a 'guest' in another application or another world where it
cannot authoritatively decide what allocator is in use. As a result it resorts
back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
memory.
# Switching Allocators
Although the compiler's default choices may work most of the time, it's often
necessary to tweak certain aspects. Overriding the compiler's decision about
which allocator is in use is done through the `#[global_allocator]` attribute:
```rust,no_run
#![feature(alloc_system, global_allocator, allocator_api)]
extern crate alloc_system;
use alloc_system::System;
#[global_allocator]
static A: System = System;
fn main() {
let a = Box::new(4); // Allocates from the system allocator.
println!("{}", a);
}
```
In this example the binary generated will not link to jemalloc by default but
instead use the system allocator. Conversely to generate a dynamic library which
uses jemalloc by default one would write:
(The `alloc_jemalloc` crate cannot be used to control the global allocator,
crate.ios `jemallocator` crate provides equivalent functionality.)
```toml
# Cargo.toml
[dependencies]
jemallocator = "0.1"
```
```rust,ignore
#![feature(global_allocator)]
#![crate_type = "dylib"]
extern crate jemallocator;
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
pub fn foo() {
let a = Box::new(4); // Allocates from jemalloc.
println!("{}", a);
}
# fn main() {}
```

View File

@ -8,17 +8,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![unstable(feature = "allocator_api", //! Memory allocation APIs
reason = "the precise API and guarantees it provides may be tweaked \
slightly, especially to possibly take into account the \ #![stable(feature = "alloc_module", since = "1.28.0")]
types being stored to make room for a future \
tracing garbage collector",
issue = "32838")]
use core::intrinsics::{min_align_of_val, size_of_val}; use core::intrinsics::{min_align_of_val, size_of_val};
use core::ptr::{NonNull, Unique}; use core::ptr::{NonNull, Unique};
use core::usize; use core::usize;
#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)] #[doc(inline)]
pub use core::alloc::*; pub use core::alloc::*;
@ -37,67 +35,112 @@ extern "Rust" {
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
} }
/// The global memory allocator.
///
/// This type implements the [`Alloc`] trait by forwarding calls
/// to the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crates default.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Copy, Clone, Default, Debug)] #[derive(Copy, Clone, Default, Debug)]
pub struct Global; pub struct Global;
#[unstable(feature = "allocator_api", issue = "32838")] /// Allocate memory with the global allocator.
#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] ///
pub type Heap = Global; /// This function forwards calls to the [`GlobalAlloc::alloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
#[unstable(feature = "allocator_api", issue = "32838")] /// if there is one, or the `std` crates default.
#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] ///
#[allow(non_upper_case_globals)] /// This function is expected to be deprecated in favor of the `alloc` method
pub const Heap: Global = Global; /// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
unsafe impl GlobalAlloc for Global { /// # Safety
#[inline] ///
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { /// See [`GlobalAlloc::alloc`].
let ptr = __rust_alloc(layout.size(), layout.align()); #[stable(feature = "global_alloc", since = "1.28.0")]
ptr as *mut Opaque #[inline]
} pub unsafe fn alloc(layout: Layout) -> *mut u8 {
__rust_alloc(layout.size(), layout.align())
#[inline]
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
__rust_dealloc(ptr as *mut u8, layout.size(), layout.align())
}
#[inline]
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size);
ptr as *mut Opaque
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
let ptr = __rust_alloc_zeroed(layout.size(), layout.align());
ptr as *mut Opaque
}
} }
/// Deallocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::dealloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crates default.
///
/// This function is expected to be deprecated in favor of the `dealloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::dealloc`].
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
__rust_dealloc(ptr, layout.size(), layout.align())
}
/// Reallocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::realloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crates default.
///
/// This function is expected to be deprecated in favor of the `realloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::realloc`].
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
__rust_realloc(ptr, layout.size(), layout.align(), new_size)
}
/// Allocate zero-initialized memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crates default.
///
/// This function is expected to be deprecated in favor of the `alloc_zeroed` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::alloc_zeroed`].
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
__rust_alloc_zeroed(layout.size(), layout.align())
}
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for Global { unsafe impl Alloc for Global {
#[inline] #[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) NonNull::new(alloc(layout)).ok_or(AllocErr)
} }
#[inline] #[inline]
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) { unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) dealloc(ptr.as_ptr(), layout)
} }
#[inline] #[inline]
unsafe fn realloc(&mut self, unsafe fn realloc(&mut self,
ptr: NonNull<Opaque>, ptr: NonNull<u8>,
layout: Layout, layout: Layout,
new_size: usize) new_size: usize)
-> Result<NonNull<Opaque>, AllocErr> -> Result<NonNull<u8>, AllocErr>
{ {
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
} }
#[inline] #[inline]
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr)
} }
} }
@ -111,9 +154,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
align as *mut u8 align as *mut u8
} else { } else {
let layout = Layout::from_size_align_unchecked(size, align); let layout = Layout::from_size_align_unchecked(size, align);
let ptr = Global.alloc(layout); let ptr = alloc(layout);
if !ptr.is_null() { if !ptr.is_null() {
ptr as *mut u8 ptr
} else { } else {
oom(layout) oom(layout)
} }
@ -129,10 +172,23 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary. // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
if size != 0 { if size != 0 {
let layout = Layout::from_size_align_unchecked(size, align); let layout = Layout::from_size_align_unchecked(size, align);
Global.dealloc(ptr as *mut Opaque, layout); dealloc(ptr as *mut u8, layout);
} }
} }
/// Abort on memory allocation error or failure.
///
/// Callers of memory allocation APIs wishing to abort computation
/// in response to an allocation error are encouraged to call this function,
/// rather than directly invoking `panic!` or similar.
///
/// The default behavior of this function is to print a message to standard error
/// and abort the process.
/// It can be replaced with [`set_oom_hook`] and [`take_oom_hook`].
///
/// [`set_oom_hook`]: ../../std/alloc/fn.set_oom_hook.html
/// [`take_oom_hook`]: ../../std/alloc/fn.take_oom_hook.html
#[stable(feature = "global_alloc", since = "1.28.0")]
#[rustc_allocator_nounwind] #[rustc_allocator_nounwind]
pub fn oom(layout: Layout) -> ! { pub fn oom(layout: Layout) -> ! {
#[allow(improper_ctypes)] #[allow(improper_ctypes)]

View File

@ -519,7 +519,7 @@ impl<T: ?Sized> Arc<T> {
if self.inner().weak.fetch_sub(1, Release) == 1 { if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire); atomic::fence(Acquire);
Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()))
} }
} }
@ -639,7 +639,7 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
let slice = from_raw_parts_mut(self.elems, self.n_elems); let slice = from_raw_parts_mut(self.elems, self.n_elems);
ptr::drop_in_place(slice); ptr::drop_in_place(slice);
Global.dealloc(self.mem.as_opaque(), self.layout.clone()); Global.dealloc(self.mem.cast(), self.layout.clone());
} }
} }
} }
@ -1196,7 +1196,7 @@ impl<T: ?Sized> Drop for Weak<T> {
if self.inner().weak.fetch_sub(1, Release) == 1 { if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire); atomic::fence(Acquire);
unsafe { unsafe {
Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()))
} }
} }
} }

View File

@ -287,7 +287,7 @@ impl<K, V> Root<K, V> {
self.as_mut().as_leaf_mut().parent = ptr::null(); self.as_mut().as_leaf_mut().parent = ptr::null();
unsafe { unsafe {
Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::<InternalNode<K, V>>()); Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>());
} }
} }
} }
@ -478,7 +478,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
debug_assert!(!self.is_shared_root()); debug_assert!(!self.is_shared_root());
let node = self.node; let node = self.node;
let ret = self.ascend().ok(); let ret = self.ascend().ok();
Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>()); Global.dealloc(node.cast(), Layout::new::<LeafNode<K, V>>());
ret ret
} }
} }
@ -499,7 +499,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
> { > {
let node = self.node; let node = self.node;
let ret = self.ascend().ok(); let ret = self.ascend().ok();
Global.dealloc(node.as_opaque(), Layout::new::<InternalNode<K, V>>()); Global.dealloc(node.cast(), Layout::new::<InternalNode<K, V>>());
ret ret
} }
} }
@ -1321,12 +1321,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
} }
Global.dealloc( Global.dealloc(
right_node.node.as_opaque(), right_node.node.cast(),
Layout::new::<InternalNode<K, V>>(), Layout::new::<InternalNode<K, V>>(),
); );
} else { } else {
Global.dealloc( Global.dealloc(
right_node.node.as_opaque(), right_node.node.cast(),
Layout::new::<LeafNode<K, V>>(), Layout::new::<LeafNode<K, V>>(),
); );
} }

View File

@ -1,110 +0,0 @@
// Copyright 2014-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.
#![allow(deprecated)]
pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Opaque};
use core::alloc::Alloc as CoreAlloc;
use core::ptr::NonNull;
#[doc(hidden)]
pub mod __core {
pub use core::*;
}
#[derive(Debug)]
pub struct Excess(pub *mut u8, pub usize);
/// Compatibility with older versions of #[global_allocator] during bootstrap
pub unsafe trait Alloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>;
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout);
fn oom(&mut self, err: AllocErr) -> !;
fn usable_size(&self, layout: &Layout) -> (usize, usize);
unsafe fn realloc(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<*mut u8, AllocErr>;
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>;
unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr>;
unsafe fn realloc_excess(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<Excess, AllocErr>;
unsafe fn grow_in_place(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<(), CannotReallocInPlace>;
unsafe fn shrink_in_place(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<(), CannotReallocInPlace>;
}
unsafe impl<T> Alloc for T where T: CoreAlloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
CoreAlloc::alloc(self, layout).map(|ptr| ptr.cast().as_ptr())
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
CoreAlloc::dealloc(self, ptr, layout)
}
fn oom(&mut self, _: AllocErr) -> ! {
unsafe { ::core::intrinsics::abort() }
}
fn usable_size(&self, layout: &Layout) -> (usize, usize) {
CoreAlloc::usable_size(self, layout)
}
unsafe fn realloc(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<*mut u8, AllocErr> {
let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr())
}
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
CoreAlloc::alloc_zeroed(self, layout).map(|ptr| ptr.cast().as_ptr())
}
unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
CoreAlloc::alloc_excess(self, layout)
.map(|e| Excess(e.0 .cast().as_ptr(), e.1))
}
unsafe fn realloc_excess(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<Excess, AllocErr> {
let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size())
.map(|e| Excess(e.0 .cast().as_ptr(), e.1))
}
unsafe fn grow_in_place(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<(), CannotReallocInPlace> {
let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size())
}
unsafe fn shrink_in_place(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<(), CannotReallocInPlace> {
let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size())
}
}

View File

@ -151,18 +151,10 @@ pub mod allocator {
pub mod alloc; pub mod alloc;
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
/// Use the `alloc` module instead.
pub mod heap {
pub use alloc::*;
}
#[unstable(feature = "futures_api", #[unstable(feature = "futures_api",
reason = "futures in libcore are unstable", reason = "futures in libcore are unstable",
issue = "50547")] issue = "50547")]
pub mod task; pub mod task;
// Primitive types using the heaps above // Primitive types using the heaps above
// Need to conditionally define the mod from `boxed.rs` to avoid // Need to conditionally define the mod from `boxed.rs` to avoid

View File

@ -93,7 +93,7 @@ impl<T, A: Alloc> RawVec<T, A> {
// handles ZSTs and `cap = 0` alike // handles ZSTs and `cap = 0` alike
let ptr = if alloc_size == 0 { let ptr = if alloc_size == 0 {
NonNull::<T>::dangling().as_opaque() NonNull::<T>::dangling()
} else { } else {
let align = mem::align_of::<T>(); let align = mem::align_of::<T>();
let layout = Layout::from_size_align(alloc_size, align).unwrap(); let layout = Layout::from_size_align(alloc_size, align).unwrap();
@ -103,13 +103,13 @@ impl<T, A: Alloc> RawVec<T, A> {
a.alloc(layout) a.alloc(layout)
}; };
match result { match result {
Ok(ptr) => ptr, Ok(ptr) => ptr.cast(),
Err(_) => oom(layout), Err(_) => oom(layout),
} }
}; };
RawVec { RawVec {
ptr: ptr.cast().into(), ptr: ptr.into(),
cap, cap,
a, a,
} }
@ -314,7 +314,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let new_cap = 2 * self.cap; let new_cap = 2 * self.cap;
let new_size = new_cap * elem_size; let new_size = new_cap * elem_size;
alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(), let ptr_res = self.a.realloc(NonNull::from(self.ptr).cast(),
cur, cur,
new_size); new_size);
match ptr_res { match ptr_res {
@ -373,7 +373,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let new_cap = 2 * self.cap; let new_cap = 2 * self.cap;
let new_size = new_cap * elem_size; let new_size = new_cap * elem_size;
alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { match self.a.grow_in_place(NonNull::from(self.ptr).cast(), old_layout, new_size) {
Ok(_) => { Ok(_) => {
// We can't directly divide `size`. // We can't directly divide `size`.
self.cap = new_cap; self.cap = new_cap;
@ -546,7 +546,7 @@ impl<T, A: Alloc> RawVec<T, A> {
// FIXME: may crash and burn on over-reserve // FIXME: may crash and burn on over-reserve
alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow()); alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow());
match self.a.grow_in_place( match self.a.grow_in_place(
NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(), NonNull::from(self.ptr).cast(), old_layout, new_layout.size(),
) { ) {
Ok(_) => { Ok(_) => {
self.cap = new_cap; self.cap = new_cap;
@ -607,7 +607,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let new_size = elem_size * amount; let new_size = elem_size * amount;
let align = mem::align_of::<T>(); let align = mem::align_of::<T>();
let old_layout = Layout::from_size_align_unchecked(old_size, align); let old_layout = Layout::from_size_align_unchecked(old_size, align);
match self.a.realloc(NonNull::from(self.ptr).as_opaque(), match self.a.realloc(NonNull::from(self.ptr).cast(),
old_layout, old_layout,
new_size) { new_size) {
Ok(p) => self.ptr = p.cast().into(), Ok(p) => self.ptr = p.cast().into(),
@ -667,7 +667,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let res = match self.current_layout() { let res = match self.current_layout() {
Some(layout) => { Some(layout) => {
debug_assert!(new_layout.align() == layout.align()); debug_assert!(new_layout.align() == layout.align());
self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) self.a.realloc(NonNull::from(self.ptr).cast(), layout, new_layout.size())
} }
None => self.a.alloc(new_layout), None => self.a.alloc(new_layout),
}; };
@ -710,7 +710,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let elem_size = mem::size_of::<T>(); let elem_size = mem::size_of::<T>();
if elem_size != 0 { if elem_size != 0 {
if let Some(layout) = self.current_layout() { if let Some(layout) = self.current_layout() {
self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout); self.a.dealloc(NonNull::from(self.ptr).cast(), layout);
} }
} }
} }
@ -753,7 +753,6 @@ fn capacity_overflow() -> ! {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use alloc::Opaque;
#[test] #[test]
fn allocator_param() { fn allocator_param() {
@ -773,7 +772,7 @@ mod tests {
// before allocation attempts start failing. // before allocation attempts start failing.
struct BoundedAlloc { fuel: usize } struct BoundedAlloc { fuel: usize }
unsafe impl Alloc for BoundedAlloc { unsafe impl Alloc for BoundedAlloc {
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
let size = layout.size(); let size = layout.size();
if size > self.fuel { if size > self.fuel {
return Err(AllocErr); return Err(AllocErr);
@ -783,7 +782,7 @@ mod tests {
err @ Err(_) => err, err @ Err(_) => err,
} }
} }
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) { unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
Global.dealloc(ptr, layout) Global.dealloc(ptr, layout)
} }
} }

View File

@ -259,7 +259,7 @@ use core::ops::CoerceUnsized;
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::convert::From; use core::convert::From;
use alloc::{Global, Alloc, Layout, Opaque, box_free, oom}; use alloc::{Global, Alloc, Layout, box_free, oom};
use string::String; use string::String;
use vec::Vec; use vec::Vec;
@ -732,7 +732,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
// In the event of a panic, elements that have been written // In the event of a panic, elements that have been written
// into the new RcBox will be dropped, then the memory freed. // into the new RcBox will be dropped, then the memory freed.
struct Guard<T> { struct Guard<T> {
mem: NonNull<Opaque>, mem: NonNull<u8>,
elems: *mut T, elems: *mut T,
layout: Layout, layout: Layout,
n_elems: usize, n_elems: usize,
@ -755,7 +755,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
let v_ptr = v as *const [T]; let v_ptr = v as *const [T];
let ptr = Self::allocate_for_ptr(v_ptr); let ptr = Self::allocate_for_ptr(v_ptr);
let mem = ptr as *mut _ as *mut Opaque; let mem = ptr as *mut _ as *mut u8;
let layout = Layout::for_value(&*ptr); let layout = Layout::for_value(&*ptr);
// Pointer to first element // Pointer to first element
@ -839,7 +839,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
self.dec_weak(); self.dec_weak();
if self.weak() == 0 { if self.weak() == 0 {
Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
} }
} }
} }
@ -1263,7 +1263,7 @@ impl<T: ?Sized> Drop for Weak<T> {
// the weak count starts at 1, and will only go to zero if all // the weak count starts at 1, and will only go to zero if all
// the strong pointers have disappeared. // the strong pointers have disappeared.
if self.weak() == 0 { if self.weak() == 0 {
Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
} }
} }
} }

View File

@ -11,9 +11,8 @@
#![no_std] #![no_std]
#![allow(unused_attributes)] #![allow(unused_attributes)]
#![unstable(feature = "alloc_jemalloc", #![unstable(feature = "alloc_jemalloc",
reason = "this library is unlikely to be stabilized in its current \ reason = "implementation detail of std, does not provide any public API",
form or name", issue = "0")]
issue = "27783")]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(libc)] #![feature(libc)]
#![feature(linkage)] #![feature(linkage)]

View File

@ -14,7 +14,6 @@
reason = "this library is unlikely to be stabilized in its current \ reason = "this library is unlikely to be stabilized in its current \
form or name", form or name",
issue = "32838")] issue = "32838")]
#![feature(global_allocator)]
#![feature(allocator_api)] #![feature(allocator_api)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(staged_api)] #![feature(staged_api)]
@ -41,54 +40,78 @@ const MIN_ALIGN: usize = 8;
#[allow(dead_code)] #[allow(dead_code)]
const MIN_ALIGN: usize = 16; const MIN_ALIGN: usize = 16;
use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque}; use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout};
use core::ptr::NonNull; use core::ptr::NonNull;
#[unstable(feature = "allocator_api", issue = "32838")] /// 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; pub struct System;
#[unstable(feature = "allocator_api", issue = "32838")] #[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for System { unsafe impl Alloc for System {
#[inline] #[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
} }
#[inline] #[inline]
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
} }
#[inline] #[inline]
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) { unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
} }
#[inline] #[inline]
unsafe fn realloc(&mut self, unsafe fn realloc(&mut self,
ptr: NonNull<Opaque>, ptr: NonNull<u8>,
layout: Layout, layout: Layout,
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> { new_size: usize) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(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"))] #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
mod realloc_fallback { mod realloc_fallback {
use core::alloc::{GlobalAlloc, Opaque, Layout}; use core::alloc::{GlobalAlloc, Layout};
use core::cmp; use core::cmp;
use core::ptr; use core::ptr;
impl super::System { impl super::System {
pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout, pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
new_size: usize) -> *mut Opaque { new_size: usize) -> *mut u8 {
// Docs for GlobalAlloc::realloc require this to be valid: // Docs for GlobalAlloc::realloc require this to be valid:
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
let new_ptr = GlobalAlloc::alloc(self, new_layout); let new_ptr = GlobalAlloc::alloc(self, new_layout);
if !new_ptr.is_null() { if !new_ptr.is_null() {
let size = cmp::min(old_layout.size(), new_size); let size = cmp::min(old_layout.size(), new_size);
ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size); ptr::copy_nonoverlapping(ptr, new_ptr, size);
GlobalAlloc::dealloc(self, ptr, old_layout); GlobalAlloc::dealloc(self, ptr, old_layout);
} }
new_ptr new_ptr
@ -104,21 +127,19 @@ mod platform {
use MIN_ALIGN; use MIN_ALIGN;
use System; use System;
use core::alloc::{GlobalAlloc, Layout, Opaque}; use core::alloc::{GlobalAlloc, Layout};
#[unstable(feature = "allocator_api", issue = "32838")] #[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System { unsafe impl GlobalAlloc for System {
#[inline] #[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::malloc(layout.size()) as *mut Opaque libc::malloc(layout.size()) as *mut u8
} else { } else {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
if layout.align() > (1 << 31) { if layout.align() > (1 << 31) {
// FIXME: use Opaque::null_mut return ptr::null_mut()
// https://github.com/rust-lang/rust/issues/49659
return 0 as *mut Opaque
} }
} }
aligned_malloc(&layout) aligned_malloc(&layout)
@ -126,27 +147,27 @@ mod platform {
} }
#[inline] #[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::calloc(layout.size(), 1) as *mut Opaque libc::calloc(layout.size(), 1) as *mut u8
} else { } else {
let ptr = self.alloc(layout.clone()); let ptr = self.alloc(layout.clone());
if !ptr.is_null() { if !ptr.is_null() {
ptr::write_bytes(ptr as *mut u8, 0, layout.size()); ptr::write_bytes(ptr, 0, layout.size());
} }
ptr ptr
} }
} }
#[inline] #[inline]
unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
libc::free(ptr as *mut libc::c_void) libc::free(ptr as *mut libc::c_void)
} }
#[inline] #[inline]
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= new_size { if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
} else { } else {
self.realloc_fallback(ptr, layout, new_size) self.realloc_fallback(ptr, layout, new_size)
} }
@ -155,7 +176,7 @@ mod platform {
#[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))]
#[inline] #[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
// On android we currently target API level 9 which unfortunately // On android we currently target API level 9 which unfortunately
// doesn't have the `posix_memalign` API used below. Instead we use // doesn't have the `posix_memalign` API used below. Instead we use
// `memalign`, but this unfortunately has the property on some systems // `memalign`, but this unfortunately has the property on some systems
@ -173,19 +194,18 @@ mod platform {
// [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
// [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
// /memory/aligned_memory.cc // /memory/aligned_memory.cc
libc::memalign(layout.align(), layout.size()) as *mut Opaque libc::memalign(layout.align(), layout.size()) as *mut u8
} }
#[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))]
#[inline] #[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
let mut out = ptr::null_mut(); let mut out = ptr::null_mut();
let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
if ret != 0 { if ret != 0 {
// FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659 ptr::null_mut()
0 as *mut Opaque
} else { } else {
out as *mut Opaque out as *mut u8
} }
} }
} }
@ -195,7 +215,7 @@ mod platform {
mod platform { mod platform {
use MIN_ALIGN; use MIN_ALIGN;
use System; use System;
use core::alloc::{GlobalAlloc, Opaque, Layout}; use core::alloc::{GlobalAlloc, Layout};
type LPVOID = *mut u8; type LPVOID = *mut u8;
type HANDLE = LPVOID; type HANDLE = LPVOID;
@ -227,7 +247,7 @@ mod platform {
} }
#[inline] #[inline]
unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque { unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
let ptr = if layout.align() <= MIN_ALIGN { let ptr = if layout.align() <= MIN_ALIGN {
HeapAlloc(GetProcessHeap(), flags, layout.size()) HeapAlloc(GetProcessHeap(), flags, layout.size())
} else { } else {
@ -239,29 +259,29 @@ mod platform {
align_ptr(ptr, layout.align()) align_ptr(ptr, layout.align())
} }
}; };
ptr as *mut Opaque ptr as *mut u8
} }
#[unstable(feature = "allocator_api", issue = "32838")] #[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System { unsafe impl GlobalAlloc for System {
#[inline] #[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
allocate_with_flags(layout, 0) allocate_with_flags(layout, 0)
} }
#[inline] #[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
allocate_with_flags(layout, HEAP_ZERO_MEMORY) allocate_with_flags(layout, HEAP_ZERO_MEMORY)
} }
#[inline] #[inline]
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if layout.align() <= MIN_ALIGN { if layout.align() <= MIN_ALIGN {
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}", debug_assert!(err != 0, "Failed to free heap memory: {}",
GetLastError()); GetLastError());
} else { } else {
let header = get_header(ptr as *mut u8); let header = get_header(ptr);
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}", debug_assert!(err != 0, "Failed to free heap memory: {}",
GetLastError()); GetLastError());
@ -269,9 +289,9 @@ mod platform {
} }
#[inline] #[inline]
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN { if layout.align() <= MIN_ALIGN {
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
} else { } else {
self.realloc_fallback(ptr, layout, new_size) self.realloc_fallback(ptr, layout, new_size)
} }
@ -300,32 +320,32 @@ mod platform {
mod platform { mod platform {
extern crate dlmalloc; extern crate dlmalloc;
use core::alloc::{GlobalAlloc, Layout, Opaque}; use core::alloc::{GlobalAlloc, Layout};
use System; use System;
// No need for synchronization here as wasm is currently single-threaded // No need for synchronization here as wasm is currently single-threaded
static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT; static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
#[unstable(feature = "allocator_api", issue = "32838")] #[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System { unsafe impl GlobalAlloc for System {
#[inline] #[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque DLMALLOC.malloc(layout.size(), layout.align())
} }
#[inline] #[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque DLMALLOC.calloc(layout.size(), layout.align())
} }
#[inline] #[inline]
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align()) DLMALLOC.free(ptr, layout.size(), layout.align())
} }
#[inline] #[inline]
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
} }
} }
} }

View File

@ -8,12 +8,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![unstable(feature = "allocator_api", //! Memory allocation APIs
reason = "the precise API and guarantees it provides may be tweaked \
slightly, especially to possibly take into account the \ #![stable(feature = "alloc_module", since = "1.28.0")]
types being stored to make room for a future \
tracing garbage collector",
issue = "32838")]
use cmp; use cmp;
use fmt; use fmt;
@ -22,30 +19,15 @@ use usize;
use ptr::{self, NonNull}; use ptr::{self, NonNull};
use num::NonZeroUsize; use num::NonZeroUsize;
extern { #[unstable(feature = "alloc_internals", issue = "0")]
/// An opaque, unsized type. Used for pointers to allocated memory. #[cfg(stage0)]
/// pub type Opaque = u8;
/// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull<Opaque>`.
/// Such pointers are similar to Cs `void*` type.
pub type Opaque;
}
impl Opaque {
/// Similar to `std::ptr::null`, which requires `T: Sized`.
pub fn null() -> *const Self {
0 as _
}
/// Similar to `std::ptr::null_mut`, which requires `T: Sized`.
pub fn null_mut() -> *mut Self {
0 as _
}
}
/// Represents the combination of a starting address and /// Represents the combination of a starting address and
/// a total capacity of the returned block. /// a total capacity of the returned block.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Debug)] #[derive(Debug)]
pub struct Excess(pub NonNull<Opaque>, pub usize); pub struct Excess(pub NonNull<u8>, pub usize);
fn size_align<T>() -> (usize, usize) { fn size_align<T>() -> (usize, usize) {
(mem::size_of::<T>(), mem::align_of::<T>()) (mem::size_of::<T>(), mem::align_of::<T>())
@ -64,6 +46,7 @@ fn size_align<T>() -> (usize, usize) {
/// requests have positive size. A caller to the `Alloc::alloc` /// requests have positive size. A caller to the `Alloc::alloc`
/// method must either ensure that conditions like this are met, or /// method must either ensure that conditions like this are met, or
/// use specific allocators with looser requirements.) /// use specific allocators with looser requirements.)
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Layout { pub struct Layout {
// size of the requested block of memory, measured in bytes. // size of the requested block of memory, measured in bytes.
@ -89,6 +72,7 @@ impl Layout {
/// * `size`, when rounded up to the nearest multiple of `align`, /// * `size`, when rounded up to the nearest multiple of `align`,
/// must not overflow (i.e. the rounded value must be less than /// must not overflow (i.e. the rounded value must be less than
/// `usize::MAX`). /// `usize::MAX`).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline] #[inline]
pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> { pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
if !align.is_power_of_two() { if !align.is_power_of_two() {
@ -124,20 +108,24 @@ impl Layout {
/// ///
/// This function is unsafe as it does not verify the preconditions from /// This function is unsafe as it does not verify the preconditions from
/// [`Layout::from_size_align`](#method.from_size_align). /// [`Layout::from_size_align`](#method.from_size_align).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline] #[inline]
pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
} }
/// The minimum size in bytes for a memory block of this layout. /// The minimum size in bytes for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline] #[inline]
pub fn size(&self) -> usize { self.size_ } pub fn size(&self) -> usize { self.size_ }
/// The minimum byte alignment for a memory block of this layout. /// The minimum byte alignment for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline] #[inline]
pub fn align(&self) -> usize { self.align_.get() } pub fn align(&self) -> usize { self.align_.get() }
/// Constructs a `Layout` suitable for holding a value of type `T`. /// Constructs a `Layout` suitable for holding a value of type `T`.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline] #[inline]
pub fn new<T>() -> Self { pub fn new<T>() -> Self {
let (size, align) = size_align::<T>(); let (size, align) = size_align::<T>();
@ -154,6 +142,7 @@ impl Layout {
/// Produces layout describing a record that could be used to /// Produces layout describing a record that could be used to
/// allocate backing structure for `T` (which could be a trait /// allocate backing structure for `T` (which could be a trait
/// or other unsized type like a slice). /// or other unsized type like a slice).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline] #[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Self { pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
@ -181,6 +170,7 @@ impl Layout {
/// Panics if the combination of `self.size()` and the given `align` /// Panics if the combination of `self.size()` and the given `align`
/// violates the conditions listed in /// violates the conditions listed in
/// [`Layout::from_size_align`](#method.from_size_align). /// [`Layout::from_size_align`](#method.from_size_align).
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn align_to(&self, align: usize) -> Self { pub fn align_to(&self, align: usize) -> Self {
Layout::from_size_align(self.size(), cmp::max(self.align(), align)).unwrap() Layout::from_size_align(self.size(), cmp::max(self.align(), align)).unwrap()
@ -202,6 +192,7 @@ impl Layout {
/// to be less than or equal to the alignment of the starting /// to be less than or equal to the alignment of the starting
/// address for the whole allocated block of memory. One way to /// address for the whole allocated block of memory. One way to
/// satisfy this constraint is to ensure `align <= self.align()`. /// satisfy this constraint is to ensure `align <= self.align()`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn padding_needed_for(&self, align: usize) -> usize { pub fn padding_needed_for(&self, align: usize) -> usize {
let len = self.size(); let len = self.size();
@ -238,6 +229,7 @@ impl Layout {
/// of each element in the array. /// of each element in the array.
/// ///
/// On arithmetic overflow, returns `LayoutErr`. /// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
let padded_size = self.size().checked_add(self.padding_needed_for(self.align())) let padded_size = self.size().checked_add(self.padding_needed_for(self.align()))
@ -263,6 +255,7 @@ impl Layout {
/// (assuming that the record itself starts at offset 0). /// (assuming that the record itself starts at offset 0).
/// ///
/// On arithmetic overflow, returns `LayoutErr`. /// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
let new_align = cmp::max(self.align(), next.align()); let new_align = cmp::max(self.align(), next.align());
@ -289,6 +282,7 @@ impl Layout {
/// aligned. /// aligned.
/// ///
/// On arithmetic overflow, returns `LayoutErr`. /// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> { pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
@ -310,6 +304,7 @@ impl Layout {
/// `extend`.) /// `extend`.)
/// ///
/// On arithmetic overflow, returns `LayoutErr`. /// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
let new_size = self.size().checked_add(next.size()) let new_size = self.size().checked_add(next.size())
@ -321,6 +316,7 @@ impl Layout {
/// Creates a layout describing the record for a `[T; n]`. /// Creates a layout describing the record for a `[T; n]`.
/// ///
/// On arithmetic overflow, returns `LayoutErr`. /// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline] #[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutErr> { pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
Layout::new::<T>() Layout::new::<T>()
@ -332,28 +328,33 @@ impl Layout {
} }
} }
/// The parameters given to `Layout::from_size_align` do not satisfy /// The parameters given to `Layout::from_size_align`
/// its documented constraints. /// or some other `Layout` constructor
/// do not satisfy its documented constraints.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutErr { pub struct LayoutErr {
private: () private: ()
} }
// (we need this for downstream impl of trait Error) // (we need this for downstream impl of trait Error)
#[stable(feature = "alloc_layout", since = "1.28.0")]
impl fmt::Display for LayoutErr { impl fmt::Display for LayoutErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("invalid parameters to Layout::from_size_align") f.write_str("invalid parameters to Layout::from_size_align")
} }
} }
/// The `AllocErr` error specifies whether an allocation failure is /// The `AllocErr` error indicates an allocation failure
/// specifically due to resource exhaustion or if it is due to /// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this /// something wrong when combining the given input arguments with this
/// allocator. /// allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr; pub struct AllocErr;
// (we need this for downstream impl of trait Error) // (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocErr { impl fmt::Display for AllocErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("memory allocation failed") f.write_str("memory allocation failed")
@ -363,9 +364,11 @@ impl fmt::Display for AllocErr {
/// The `CannotReallocInPlace` error is used when `grow_in_place` or /// The `CannotReallocInPlace` error is used when `grow_in_place` or
/// `shrink_in_place` were unable to reuse the given memory block for /// `shrink_in_place` were unable to reuse the given memory block for
/// a requested layout. /// a requested layout.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct CannotReallocInPlace; pub struct CannotReallocInPlace;
#[unstable(feature = "allocator_api", issue = "32838")]
impl CannotReallocInPlace { impl CannotReallocInPlace {
pub fn description(&self) -> &str { pub fn description(&self) -> &str {
"cannot reallocate allocator's memory in place" "cannot reallocate allocator's memory in place"
@ -373,6 +376,7 @@ impl CannotReallocInPlace {
} }
// (we need this for downstream impl of trait Error) // (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for CannotReallocInPlace { impl fmt::Display for CannotReallocInPlace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description()) write!(f, "{}", self.description())
@ -380,6 +384,7 @@ impl fmt::Display for CannotReallocInPlace {
} }
/// Augments `AllocErr` with a CapacityOverflow variant. /// Augments `AllocErr` with a CapacityOverflow variant.
// FIXME: should this be in libcore or liballoc?
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub enum CollectionAllocErr { pub enum CollectionAllocErr {
@ -406,32 +411,134 @@ impl From<LayoutErr> for CollectionAllocErr {
} }
} }
/// A memory allocator that can be registered to be the one backing `std::alloc::Global` /// A memory allocator that can be registered as the standard librarys default
/// though the `#[global_allocator]` attributes. /// though the `#[global_allocator]` attributes.
///
/// Some of the methods require that a memory block be *currently
/// allocated* via an allocator. This means that:
///
/// * the starting address for that memory block was previously
/// returned by a previous call to an allocation method
/// such as `alloc`, and
///
/// * the memory block has not been subsequently deallocated, where
/// blocks are deallocated either by being passed to a deallocation
/// method such as `dealloc` or by being
/// passed to a reallocation method that returns a non-null pointer.
///
///
/// # Example
///
/// ```no_run
/// use std::alloc::{GlobalAlloc, Layout, alloc};
/// use std::ptr::null_mut;
///
/// struct MyAllocator;
///
/// unsafe impl GlobalAlloc for MyAllocator {
/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
/// }
///
/// #[global_allocator]
/// static A: MyAllocator = MyAllocator;
///
/// fn main() {
/// unsafe {
/// assert!(alloc(Layout::new::<u32>()).is_null())
/// }
/// }
/// ```
///
/// # Unsafety
///
/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
/// implementors must ensure that they adhere to these contracts:
///
/// * It's undefined behavior if global allocators unwind. This restriction may
/// be lifted in the future, but currently a panic from any of these
/// functions may lead to memory unsafety.
///
/// * `Layout` queries and calculations in general must be correct. Callers of
/// this trait are allowed to rely on the contracts defined on each method,
/// and implementors must ensure such contracts remain true.
#[stable(feature = "global_alloc", since = "1.28.0")]
pub unsafe trait GlobalAlloc { pub unsafe trait GlobalAlloc {
/// Allocate memory as described by the given `layout`. /// Allocate memory as described by the given `layout`.
/// ///
/// Returns a pointer to newly-allocated memory, /// Returns a pointer to newly-allocated memory,
/// or NULL to indicate allocation failure. /// or null to indicate allocation failure.
/// ///
/// # Safety /// # Safety
/// ///
/// **FIXME:** what are the exact requirements? /// This function is unsafe because undefined behavior can result
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque; /// if the caller does not ensure that `layout` has non-zero size.
///
/// (Extension subtraits might provide more specific bounds on
/// behavior, e.g. guarantee a sentinel address or a null pointer
/// in response to a zero-size allocation request.)
///
/// The allocated block of memory may or may not be initialized.
///
/// # Errors
///
/// Returning a null pointer indicates that either memory is exhausted
/// or `layout` does not meet allocator's size or alignment constraints.
///
/// Implementations are encouraged to return null on memory
/// exhaustion rather than aborting, but this is not
/// a strict requirement. (Specifically: it is *legal* to
/// implement this trait atop an underlying native allocation
/// library that aborts on memory exhaustion.)
///
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the [`oom`] function,
/// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
#[stable(feature = "global_alloc", since = "1.28.0")]
unsafe fn alloc(&self, layout: Layout) -> *mut u8;
/// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
/// ///
/// # Safety /// # Safety
/// ///
/// **FIXME:** what are the exact requirements? /// This function is unsafe because undefined behavior can result
/// In particular around layout *fit*. (See docs for the `Alloc` trait.) /// if the caller does not ensure all of the following:
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout); ///
/// * `ptr` must denote a block of memory currently allocated via
/// this allocator,
///
/// * `layout` must be the same layout that was used
/// to allocated that block of memory,
#[stable(feature = "global_alloc", since = "1.28.0")]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { /// Behaves like `alloc`, but also ensures that the contents
/// are set to zero before being returned.
///
/// # Safety
///
/// This function is unsafe for the same reasons that `alloc` is.
/// However the allocated block of memory is guaranteed to be initialized.
///
/// # Errors
///
/// Returning a null pointer indicates that either memory is exhausted
/// or `layout` does not meet allocator's size or alignment constraints,
/// just as in `alloc`.
///
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the [`oom`] function,
/// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
#[stable(feature = "global_alloc", since = "1.28.0")]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let size = layout.size(); let size = layout.size();
let ptr = self.alloc(layout); let ptr = self.alloc(layout);
if !ptr.is_null() { if !ptr.is_null() {
ptr::write_bytes(ptr as *mut u8, 0, size); ptr::write_bytes(ptr, 0, size);
} }
ptr ptr
} }
@ -439,26 +546,61 @@ pub unsafe trait GlobalAlloc {
/// Shink or grow a block of memory to the given `new_size`. /// Shink or grow a block of memory to the given `new_size`.
/// The block is described by the given `ptr` pointer and `layout`. /// The block is described by the given `ptr` pointer and `layout`.
/// ///
/// Return a new pointer (which may or may not be the same as `ptr`), /// If this returns a non-null pointer, then ownership of the memory block
/// or NULL to indicate reallocation failure. /// referenced by `ptr` has been transferred to this alloctor.
/// The memory may or may not have been deallocated,
/// and should be considered unusable (unless of course it was
/// transferred back to the caller again via the return value of
/// this method).
/// ///
/// If reallocation is successful, the old `ptr` pointer is considered /// If this method returns null, then ownership of the memory
/// to have been deallocated. /// block has not been transferred to this allocator, and the
/// contents of the memory block are unaltered.
/// ///
/// # Safety /// # Safety
/// ///
/// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, /// This function is unsafe because undefined behavior can result
/// if the caller does not ensure all of the following:
///
/// * `ptr` must be currently allocated via this allocator,
///
/// * `layout` must be the same layout that was used
/// to allocated that block of memory,
///
/// * `new_size` must be greater than zero.
///
/// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
/// must not overflow (i.e. the rounded value must be less than `usize::MAX`). /// must not overflow (i.e. the rounded value must be less than `usize::MAX`).
/// ///
/// **FIXME:** what are the exact requirements? /// (Extension subtraits might provide more specific bounds on
/// In particular around layout *fit*. (See docs for the `Alloc` trait.) /// behavior, e.g. guarantee a sentinel address or a null pointer
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { /// in response to a zero-size allocation request.)
///
/// # Errors
///
/// Returns null if the new layout does not meet the size
/// and alignment constraints of the allocator, or if reallocation
/// otherwise fails.
///
/// Implementations are encouraged to return null on memory
/// exhaustion rather than panicking or aborting, but this is not
/// a strict requirement. (Specifically: it is *legal* to
/// implement this trait atop an underlying native allocation
/// library that aborts on memory exhaustion.)
///
/// Clients wishing to abort computation in response to a
/// reallocation error are encouraged to call the [`oom`] function,
/// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
#[stable(feature = "global_alloc", since = "1.28.0")]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
let new_ptr = self.alloc(new_layout); let new_ptr = self.alloc(new_layout);
if !new_ptr.is_null() { if !new_ptr.is_null() {
ptr::copy_nonoverlapping( ptr::copy_nonoverlapping(
ptr as *const u8, ptr,
new_ptr as *mut u8, new_ptr,
cmp::min(layout.size(), new_size), cmp::min(layout.size(), new_size),
); );
self.dealloc(ptr, layout); self.dealloc(ptr, layout);
@ -540,27 +682,22 @@ pub unsafe trait GlobalAlloc {
/// retain their validity until at least the instance of `Alloc` is dropped /// retain their validity until at least the instance of `Alloc` is dropped
/// itself. /// itself.
/// ///
/// * It's undefined behavior if global allocators unwind. This restriction may
/// be lifted in the future, but currently a panic from any of these
/// functions may lead to memory unsafety. Note that as of the time of this
/// writing allocators *not* intending to be global allocators can still panic
/// in their implementation without violating memory safety.
///
/// * `Layout` queries and calculations in general must be correct. Callers of /// * `Layout` queries and calculations in general must be correct. Callers of
/// this trait are allowed to rely on the contracts defined on each method, /// this trait are allowed to rely on the contracts defined on each method,
/// and implementors must ensure such contracts remain true. /// and implementors must ensure such contracts remain true.
/// ///
/// Note that this list may get tweaked over time as clarifications are made in /// Note that this list may get tweaked over time as clarifications are made in
/// the future. Additionally global allocators may gain unique requirements for /// the future.
/// how to safely implement one in the future as well. #[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe trait Alloc { pub unsafe trait Alloc {
// (Note: existing allocators have unspecified but well-defined // (Note: some existing allocators have unspecified but well-defined
// behavior in response to a zero size allocation request ; // behavior in response to a zero size allocation request ;
// e.g. in C, `malloc` of 0 will either return a null pointer or a // e.g. in C, `malloc` of 0 will either return a null pointer or a
// unique pointer, but will not have arbitrary undefined // unique pointer, but will not have arbitrary undefined
// behavior. Rust should consider revising the alloc::heap crate // behavior.
// to reflect this reality.) // However in jemalloc for example,
// `mallocx(0)` is documented as undefined behavior.)
/// Returns a pointer meeting the size and alignment guarantees of /// Returns a pointer meeting the size and alignment guarantees of
/// `layout`. /// `layout`.
@ -596,9 +733,11 @@ pub unsafe trait Alloc {
/// library that aborts on memory exhaustion.) /// library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an /// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom` /// allocation error are encouraged to call the [`oom`] function,
/// method, rather than directly invoking `panic!` or similar. /// rather than directly invoking `panic!` or similar.
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr>; ///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr>;
/// Deallocate the memory referenced by `ptr`. /// Deallocate the memory referenced by `ptr`.
/// ///
@ -615,7 +754,7 @@ pub unsafe trait Alloc {
/// * In addition to fitting the block of memory `layout`, the /// * In addition to fitting the block of memory `layout`, the
/// alignment of the `layout` must match the alignment used /// alignment of the `layout` must match the alignment used
/// to allocate that block of memory. /// to allocate that block of memory.
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout); unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);
// == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS ==
// usable_size // usable_size
@ -703,13 +842,15 @@ pub unsafe trait Alloc {
/// implement this trait atop an underlying native allocation /// implement this trait atop an underlying native allocation
/// library that aborts on memory exhaustion.) /// library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an /// Clients wishing to abort computation in response to a
/// reallocation error are encouraged to call the allocator's `oom` /// reallocation error are encouraged to call the [`oom`] function,
/// method, rather than directly invoking `panic!` or similar. /// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn realloc(&mut self, unsafe fn realloc(&mut self,
ptr: NonNull<Opaque>, ptr: NonNull<u8>,
layout: Layout, layout: Layout,
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> { new_size: usize) -> Result<NonNull<u8>, AllocErr> {
let old_size = layout.size(); let old_size = layout.size();
if new_size >= old_size { if new_size >= old_size {
@ -726,8 +867,8 @@ pub unsafe trait Alloc {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
let result = self.alloc(new_layout); let result = self.alloc(new_layout);
if let Ok(new_ptr) = result { if let Ok(new_ptr) = result {
ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, ptr::copy_nonoverlapping(ptr.as_ptr(),
new_ptr.as_ptr() as *mut u8, new_ptr.as_ptr(),
cmp::min(old_size, new_size)); cmp::min(old_size, new_size));
self.dealloc(ptr, layout); self.dealloc(ptr, layout);
} }
@ -748,13 +889,15 @@ pub unsafe trait Alloc {
/// constraints, just as in `alloc`. /// constraints, just as in `alloc`.
/// ///
/// Clients wishing to abort computation in response to an /// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom` /// allocation error are encouraged to call the [`oom`] function,
/// method, rather than directly invoking `panic!` or similar. /// rather than directly invoking `panic!` or similar.
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { ///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
let size = layout.size(); let size = layout.size();
let p = self.alloc(layout); let p = self.alloc(layout);
if let Ok(p) = p { if let Ok(p) = p {
ptr::write_bytes(p.as_ptr() as *mut u8, 0, size); ptr::write_bytes(p.as_ptr(), 0, size);
} }
p p
} }
@ -774,8 +917,10 @@ pub unsafe trait Alloc {
/// constraints, just as in `alloc`. /// constraints, just as in `alloc`.
/// ///
/// Clients wishing to abort computation in response to an /// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom` /// allocation error are encouraged to call the [`oom`] function,
/// method, rather than directly invoking `panic!` or similar. /// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> { unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
let usable_size = self.usable_size(&layout); let usable_size = self.usable_size(&layout);
self.alloc(layout).map(|p| Excess(p, usable_size.1)) self.alloc(layout).map(|p| Excess(p, usable_size.1))
@ -795,11 +940,13 @@ pub unsafe trait Alloc {
/// `layout` does not meet allocator's size or alignment /// `layout` does not meet allocator's size or alignment
/// constraints, just as in `realloc`. /// constraints, just as in `realloc`.
/// ///
/// Clients wishing to abort computation in response to an /// Clients wishing to abort computation in response to a
/// reallocation error are encouraged to call the allocator's `oom` /// reallocation error are encouraged to call the [`oom`] function,
/// method, rather than directly invoking `panic!` or similar. /// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn realloc_excess(&mut self, unsafe fn realloc_excess(&mut self,
ptr: NonNull<Opaque>, ptr: NonNull<u8>,
layout: Layout, layout: Layout,
new_size: usize) -> Result<Excess, AllocErr> { new_size: usize) -> Result<Excess, AllocErr> {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
@ -840,11 +987,11 @@ pub unsafe trait Alloc {
/// could fit `layout`. /// could fit `layout`.
/// ///
/// Note that one cannot pass `CannotReallocInPlace` to the `oom` /// Note that one cannot pass `CannotReallocInPlace` to the `oom`
/// method; clients are expected either to be able to recover from /// function; clients are expected either to be able to recover from
/// `grow_in_place` failures without aborting, or to fall back on /// `grow_in_place` failures without aborting, or to fall back on
/// another reallocation method before resorting to an abort. /// another reallocation method before resorting to an abort.
unsafe fn grow_in_place(&mut self, unsafe fn grow_in_place(&mut self,
ptr: NonNull<Opaque>, ptr: NonNull<u8>,
layout: Layout, layout: Layout,
new_size: usize) -> Result<(), CannotReallocInPlace> { new_size: usize) -> Result<(), CannotReallocInPlace> {
let _ = ptr; // this default implementation doesn't care about the actual address. let _ = ptr; // this default implementation doesn't care about the actual address.
@ -895,11 +1042,11 @@ pub unsafe trait Alloc {
/// could fit `layout`. /// could fit `layout`.
/// ///
/// Note that one cannot pass `CannotReallocInPlace` to the `oom` /// Note that one cannot pass `CannotReallocInPlace` to the `oom`
/// method; clients are expected either to be able to recover from /// function; clients are expected either to be able to recover from
/// `shrink_in_place` failures without aborting, or to fall back /// `shrink_in_place` failures without aborting, or to fall back
/// on another reallocation method before resorting to an abort. /// on another reallocation method before resorting to an abort.
unsafe fn shrink_in_place(&mut self, unsafe fn shrink_in_place(&mut self,
ptr: NonNull<Opaque>, ptr: NonNull<u8>,
layout: Layout, layout: Layout,
new_size: usize) -> Result<(), CannotReallocInPlace> { new_size: usize) -> Result<(), CannotReallocInPlace> {
let _ = ptr; // this default implementation doesn't care about the actual address. let _ = ptr; // this default implementation doesn't care about the actual address.
@ -943,8 +1090,10 @@ pub unsafe trait Alloc {
/// will *not* yield undefined behavior. /// will *not* yield undefined behavior.
/// ///
/// Clients wishing to abort computation in response to an /// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom` /// allocation error are encouraged to call the [`oom`] function,
/// method, rather than directly invoking `panic!` or similar. /// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr> fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr>
where Self: Sized where Self: Sized
{ {
@ -978,7 +1127,7 @@ pub unsafe trait Alloc {
{ {
let k = Layout::new::<T>(); let k = Layout::new::<T>();
if k.size() > 0 { if k.size() > 0 {
self.dealloc(ptr.as_opaque(), k); self.dealloc(ptr.cast(), k);
} }
} }
@ -1010,8 +1159,10 @@ pub unsafe trait Alloc {
/// Always returns `Err` on arithmetic overflow. /// Always returns `Err` on arithmetic overflow.
/// ///
/// Clients wishing to abort computation in response to an /// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom` /// allocation error are encouraged to call the [`oom`] function,
/// method, rather than directly invoking `panic!` or similar. /// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr> fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr>
where Self: Sized where Self: Sized
{ {
@ -1054,9 +1205,11 @@ pub unsafe trait Alloc {
/// ///
/// Always returns `Err` on arithmetic overflow. /// Always returns `Err` on arithmetic overflow.
/// ///
/// Clients wishing to abort computation in response to an /// Clients wishing to abort computation in response to a
/// reallocation error are encouraged to call the allocator's `oom` /// reallocation error are encouraged to call the [`oom`] function,
/// method, rather than directly invoking `panic!` or similar. /// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn realloc_array<T>(&mut self, unsafe fn realloc_array<T>(&mut self,
ptr: NonNull<T>, ptr: NonNull<T>,
n_old: usize, n_old: usize,
@ -1066,7 +1219,7 @@ pub unsafe trait Alloc {
match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) { match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) {
(Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => {
debug_assert!(k_old.align() == k_new.align()); debug_assert!(k_old.align() == k_new.align());
self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast) self.realloc(ptr.cast(), k_old.clone(), k_new.size()).map(NonNull::cast)
} }
_ => { _ => {
Err(AllocErr) Err(AllocErr)
@ -1099,7 +1252,7 @@ pub unsafe trait Alloc {
{ {
match Layout::array::<T>(n) { match Layout::array::<T>(n) {
Ok(ref k) if k.size() > 0 => { Ok(ref k) if k.size() > 0 => {
Ok(self.dealloc(ptr.as_opaque(), k.clone())) Ok(self.dealloc(ptr.cast(), k.clone()))
} }
_ => { _ => {
Err(AllocErr) Err(AllocErr)

View File

@ -215,13 +215,6 @@ pub mod task;
#[allow(missing_docs)] #[allow(missing_docs)]
pub mod alloc; pub mod alloc;
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
/// Use the `alloc` module instead.
pub mod heap {
pub use alloc::*;
}
// note: does not need to be public // note: does not need to be public
mod iter_private; mod iter_private;
mod nonzero; mod nonzero;

View File

@ -2922,14 +2922,6 @@ impl<T: ?Sized> NonNull<T> {
NonNull::new_unchecked(self.as_ptr() as *mut U) NonNull::new_unchecked(self.as_ptr() as *mut U)
} }
} }
/// Cast to an `Opaque` pointer
#[unstable(feature = "allocator_api", issue = "32838")]
pub fn as_opaque(self) -> NonNull<::alloc::Opaque> {
unsafe {
NonNull::new_unchecked(self.as_ptr() as _)
}
}
} }
#[stable(feature = "nonnull", since = "1.25.0")] #[stable(feature = "nonnull", since = "1.25.0")]

View File

@ -237,7 +237,7 @@ impl<'a> AllocFnFactory<'a> {
let ident = ident(); let ident = ident();
args.push(self.cx.arg(self.span, ident, self.ptr_u8())); args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
let arg = self.cx.expr_ident(self.span, ident); let arg = self.cx.expr_ident(self.span, ident);
self.cx.expr_cast(self.span, arg, self.ptr_opaque()) self.cx.expr_cast(self.span, arg, self.ptr_u8())
} }
AllocatorTy::Usize => { AllocatorTy::Usize => {
@ -281,17 +281,4 @@ impl<'a> AllocFnFactory<'a> {
let ty_u8 = self.cx.ty_path(u8); let ty_u8 = self.cx.ty_path(u8);
self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
} }
fn ptr_opaque(&self) -> P<Ty> {
let opaque = self.cx.path(
self.span,
vec![
self.core,
Ident::from_str("alloc"),
Ident::from_str("Opaque"),
],
);
let ty_opaque = self.cx.ty_path(opaque);
self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable)
}
} }

View File

@ -10,8 +10,7 @@
#![sanitizer_runtime] #![sanitizer_runtime]
#![feature(alloc_system)] #![feature(alloc_system)]
#![feature(allocator_api)] #![cfg_attr(stage0, feature(global_allocator))]
#![feature(global_allocator)]
#![feature(sanitizer_runtime)] #![feature(sanitizer_runtime)]
#![feature(staged_api)] #![feature(staged_api)]
#![no_std] #![no_std]

View File

@ -9,10 +9,9 @@
// except according to those terms. // except according to those terms.
#![sanitizer_runtime] #![sanitizer_runtime]
#![feature(sanitizer_runtime)]
#![feature(alloc_system)] #![feature(alloc_system)]
#![feature(allocator_api)] #![cfg_attr(stage0, feature(global_allocator))]
#![feature(global_allocator)] #![feature(sanitizer_runtime)]
#![feature(staged_api)] #![feature(staged_api)]
#![no_std] #![no_std]
#![unstable(feature = "sanitizer_runtime_lib", #![unstable(feature = "sanitizer_runtime_lib",

View File

@ -9,10 +9,9 @@
// except according to those terms. // except according to those terms.
#![sanitizer_runtime] #![sanitizer_runtime]
#![feature(sanitizer_runtime)]
#![feature(alloc_system)] #![feature(alloc_system)]
#![feature(allocator_api)] #![cfg_attr(stage0, feature(global_allocator))]
#![feature(global_allocator)] #![feature(sanitizer_runtime)]
#![feature(staged_api)] #![feature(staged_api)]
#![no_std] #![no_std]
#![unstable(feature = "sanitizer_runtime_lib", #![unstable(feature = "sanitizer_runtime_lib",

View File

@ -10,8 +10,7 @@
#![sanitizer_runtime] #![sanitizer_runtime]
#![feature(alloc_system)] #![feature(alloc_system)]
#![feature(allocator_api)] #![cfg_attr(stage0, feature(global_allocator))]
#![feature(global_allocator)]
#![feature(sanitizer_runtime)] #![feature(sanitizer_runtime)]
#![feature(staged_api)] #![feature(staged_api)]
#![no_std] #![no_std]

View File

@ -8,19 +8,84 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! dox //! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified.
//! The compiler may link to a version of [jemalloc] on some platforms,
//! but this is not guaranteed.
//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed
//! to use the [`System`] by default.
//!
//! [jemalloc]: https://github.com/jemalloc/jemalloc
//! [`System`]: struct.System.html
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//! System.alloc(layout)
//! }
//!
//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//! System.dealloc(ptr, layout)
//! }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//! // This `Vec` will allocate memory through `GLOBAL` above
//! let mut v = Vec::new();
//! v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallacator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.
#![unstable(issue = "32838", feature = "allocator_api")] #![stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom};
#[doc(inline)] pub use alloc_system::System;
#[doc(inline)] pub use core::alloc::*;
use core::sync::atomic::{AtomicPtr, Ordering}; use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr}; use core::{mem, ptr};
use sys_common::util::dumb_print; use sys_common::util::dumb_print;
#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;
#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[doc(inline)]
pub use alloc_system::System;
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
/// Registers a custom OOM hook, replacing any that was previously registered. /// Registers a custom OOM hook, replacing any that was previously registered.
@ -34,6 +99,7 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
/// about the allocation that failed. /// about the allocation that failed.
/// ///
/// The OOM hook is a global resource. /// The OOM hook is a global resource.
#[unstable(feature = "oom_hook", issue = "51245")]
pub fn set_oom_hook(hook: fn(Layout)) { pub fn set_oom_hook(hook: fn(Layout)) {
HOOK.store(hook as *mut (), Ordering::SeqCst); HOOK.store(hook as *mut (), Ordering::SeqCst);
} }
@ -43,6 +109,7 @@ pub fn set_oom_hook(hook: fn(Layout)) {
/// *See also the function [`set_oom_hook`].* /// *See also the function [`set_oom_hook`].*
/// ///
/// If no custom hook is registered, the default hook will be returned. /// If no custom hook is registered, the default hook will be returned.
#[unstable(feature = "oom_hook", issue = "51245")]
pub fn take_oom_hook() -> fn(Layout) { pub fn take_oom_hook() -> fn(Layout) {
let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
if hook.is_null() { if hook.is_null() {
@ -59,6 +126,7 @@ fn default_oom_hook(layout: Layout) {
#[cfg(not(test))] #[cfg(not(test))]
#[doc(hidden)] #[doc(hidden)]
#[lang = "oom"] #[lang = "oom"]
#[unstable(feature = "alloc_internals", issue = "0")]
pub extern fn rust_oom(layout: Layout) -> ! { pub extern fn rust_oom(layout: Layout) -> ! {
let hook = HOOK.load(Ordering::SeqCst); let hook = HOOK.load(Ordering::SeqCst);
let hook: fn(Layout) = if hook.is_null() { let hook: fn(Layout) = if hook.is_null() {
@ -73,8 +141,9 @@ pub extern fn rust_oom(layout: Layout) -> ! {
#[cfg(not(test))] #[cfg(not(test))]
#[doc(hidden)] #[doc(hidden)]
#[allow(unused_attributes)] #[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "0")]
pub mod __default_lib_allocator { pub mod __default_lib_allocator {
use super::{System, Layout, GlobalAlloc, Opaque}; use super::{System, Layout, GlobalAlloc};
// for symbol names src/librustc/middle/allocator.rs // for symbol names src/librustc/middle/allocator.rs
// for signatures src/librustc_allocator/lib.rs // for signatures src/librustc_allocator/lib.rs
@ -85,7 +154,7 @@ pub mod __default_lib_allocator {
#[rustc_std_internal_symbol] #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size, align); let layout = Layout::from_size_align_unchecked(size, align);
System.alloc(layout) as *mut u8 System.alloc(layout)
} }
#[no_mangle] #[no_mangle]
@ -93,7 +162,7 @@ pub mod __default_lib_allocator {
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
size: usize, size: usize,
align: usize) { align: usize) {
System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align)) System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
} }
#[no_mangle] #[no_mangle]
@ -103,13 +172,13 @@ pub mod __default_lib_allocator {
align: usize, align: usize,
new_size: usize) -> *mut u8 { new_size: usize) -> *mut u8 {
let old_layout = Layout::from_size_align_unchecked(old_size, align); let old_layout = Layout::from_size_align_unchecked(old_size, align);
System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8 System.realloc(ptr, old_layout, new_size)
} }
#[no_mangle] #[no_mangle]
#[rustc_std_internal_symbol] #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size, align); let layout = Layout::from_size_align_unchecked(size, align);
System.alloc_zeroed(layout) as *mut u8 System.alloc_zeroed(layout)
} }
} }

View File

@ -1124,7 +1124,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
let (layout, _) = calculate_layout::<K, V>(self.capacity()) let (layout, _) = calculate_layout::<K, V>(self.capacity())
.unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
unsafe { unsafe {
Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout); Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout);
// Remember how everything was allocated out of one buffer // Remember how everything was allocated out of one buffer
// during initialization? We only need one call to free here. // during initialization? We only need one call to free here.
} }

View File

@ -438,7 +438,7 @@ pub use self::hash_map::HashMap;
pub use self::hash_set::HashSet; pub use self::hash_set::HashSet;
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub use heap::CollectionAllocErr; pub use alloc::CollectionAllocErr;
mod hash; mod hash;

View File

@ -23,13 +23,13 @@
// coherence challenge (e.g., specialization, neg impls, etc) we can // coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in. // reconsider what crate these items belong in.
use alloc::{AllocErr, LayoutErr, CannotReallocInPlace};
use any::TypeId; use any::TypeId;
use borrow::Cow; use borrow::Cow;
use cell; use cell;
use char; use char;
use core::array; use core::array;
use fmt::{self, Debug, Display}; use fmt::{self, Debug, Display};
use heap::{AllocErr, LayoutErr, CannotReallocInPlace};
use mem::transmute; use mem::transmute;
use num; use num;
use str; use str;

View File

@ -264,7 +264,6 @@
#![feature(fnbox)] #![feature(fnbox)]
#![feature(futures_api)] #![feature(futures_api)]
#![feature(hashmap_internals)] #![feature(hashmap_internals)]
#![feature(heap_api)]
#![feature(int_error_internals)] #![feature(int_error_internals)]
#![feature(integer_atomics)] #![feature(integer_atomics)]
#![feature(into_cow)] #![feature(into_cow)]
@ -500,13 +499,6 @@ pub mod process;
pub mod sync; pub mod sync;
pub mod time; pub mod time;
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
/// Use the `alloc` module instead.
pub mod heap {
pub use alloc::*;
}
// Platform-abstraction modules // Platform-abstraction modules
#[macro_use] #[macro_use]
mod sys_common; mod sys_common;

View File

@ -357,8 +357,6 @@ declare_features! (
// Trait aliases // Trait aliases
(active, trait_alias, "1.24.0", Some(41517), None), (active, trait_alias, "1.24.0", Some(41517), None),
// global allocators and their internals
(active, global_allocator, "1.20.0", Some(27389), None),
// rustc internal // rustc internal
(active, allocator_internals, "1.20.0", None, None), (active, allocator_internals, "1.20.0", None, None),
@ -615,6 +613,8 @@ declare_features! (
(accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
// Termination trait in tests (RFC 1937) // Termination trait in tests (RFC 1937)
(accepted, termination_trait_test, "1.27.0", Some(48854), None), (accepted, termination_trait_test, "1.27.0", Some(48854), None),
// The #[global_allocator] attribute
(accepted, global_allocator, "1.28.0", Some(27389), None),
); );
// If you change this, please modify src/doc/unstable-book as well. You must // If you change this, please modify src/doc/unstable-book as well. You must
@ -776,11 +776,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
"the `#[rustc_const_unstable]` attribute \ "the `#[rustc_const_unstable]` attribute \
is an internal feature", is an internal feature",
cfg_fn!(rustc_const_unstable))), cfg_fn!(rustc_const_unstable))),
("global_allocator", Normal, Gated(Stability::Unstable, ("global_allocator", Normal, Ungated),
"global_allocator",
"the `#[global_allocator]` attribute is \
an experimental feature",
cfg_fn!(global_allocator))),
("default_lib_allocator", Whitelisted, Gated(Stability::Unstable, ("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
"allocator_internals", "allocator_internals",
"the `#[default_lib_allocator]` \ "the `#[default_lib_allocator]` \

View File

@ -10,7 +10,6 @@
// no-prefer-dynamic // no-prefer-dynamic
#![feature(global_allocator, allocator_api)]
#![crate_type = "rlib"] #![crate_type = "rlib"]
use std::alloc::System; use std::alloc::System;

View File

@ -10,7 +10,6 @@
// no-prefer-dynamic // no-prefer-dynamic
#![feature(global_allocator, allocator_api)]
#![crate_type = "rlib"] #![crate_type = "rlib"]
use std::alloc::System; use std::alloc::System;

View File

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(global_allocator)]
#[global_allocator] #[global_allocator]
fn foo() {} //~ ERROR: allocators must be statics fn foo() {} //~ ERROR: allocators must be statics

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(global_allocator, heap_api)]
#[global_allocator] #[global_allocator]
static A: usize = 0; static A: usize = 0;
//~^ the trait bound `usize: //~^ the trait bound `usize:

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(global_allocator, allocator_api)]
use std::alloc::System; use std::alloc::System;
#[global_allocator] #[global_allocator]

View File

@ -12,8 +12,6 @@
// no-prefer-dynamic // no-prefer-dynamic
// error-pattern: the #[global_allocator] in // error-pattern: the #[global_allocator] in
#![feature(global_allocator, allocator_api)]
extern crate system_allocator; extern crate system_allocator;
use std::alloc::System; use std::alloc::System;

View File

@ -13,7 +13,6 @@
// no-prefer-dynamic // no-prefer-dynamic
// error-pattern: the #[global_allocator] in // error-pattern: the #[global_allocator] in
#![feature(global_allocator)]
extern crate system_allocator; extern crate system_allocator;
extern crate system_allocator2; extern crate system_allocator2;

View File

@ -18,6 +18,11 @@
mod cross_crate { mod cross_crate {
extern crate lint_stability_fields; extern crate lint_stability_fields;
mod reexport {
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::lint_stability_fields::*;
}
use self::lint_stability_fields::*; use self::lint_stability_fields::*;
pub fn foo() { pub fn foo() {
@ -73,6 +78,8 @@ mod cross_crate {
// the patterns are all fine: // the patterns are all fine:
{ .. } = x; { .. } = x;
// Unstable items are still unstable even when used through a stable "pub use".
let x = reexport::Unstable2(1, 2, 3); //~ ERROR use of unstable
let x = Unstable2(1, 2, 3); //~ ERROR use of unstable let x = Unstable2(1, 2, 3); //~ ERROR use of unstable

View File

@ -16,11 +16,11 @@ use std::alloc::*;
pub struct A; pub struct A;
unsafe impl GlobalAlloc for A { unsafe impl GlobalAlloc for A {
unsafe fn alloc(&self, _: Layout) -> *mut Opaque { unsafe fn alloc(&self, _: Layout) -> *mut u8 {
loop {} loop {}
} }
unsafe fn dealloc(&self, _ptr: *mut Opaque, _: Layout) { unsafe fn dealloc(&self, _ptr: *mut u8, _: Layout) {
loop {} loop {}
} }
} }

View File

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(global_allocator)]
#![crate_type = "cdylib"] #![crate_type = "cdylib"]
extern crate bar; extern crate bar;

View File

@ -8,11 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(global_allocator, alloc_system, allocator_api)] use std::alloc::System;
extern crate alloc_system;
use std::collections::VecDeque; use std::collections::VecDeque;
use alloc_system::System;
#[global_allocator] #[global_allocator]
static ALLOCATOR: System = System; static ALLOCATOR: System = System;

View File

@ -10,7 +10,6 @@
// no-prefer-dynamic // no-prefer-dynamic
#![feature(global_allocator)]
#![crate_type = "rlib"] #![crate_type = "rlib"]
extern crate custom; extern crate custom;

View File

@ -13,18 +13,18 @@
#![feature(heap_api, allocator_api)] #![feature(heap_api, allocator_api)]
#![crate_type = "rlib"] #![crate_type = "rlib"]
use std::alloc::{GlobalAlloc, System, Layout, Opaque}; use std::alloc::{GlobalAlloc, System, Layout};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
pub struct A(pub AtomicUsize); pub struct A(pub AtomicUsize);
unsafe impl GlobalAlloc for A { unsafe impl GlobalAlloc for A {
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.0.fetch_add(1, Ordering::SeqCst); self.0.fetch_add(1, Ordering::SeqCst);
System.alloc(layout) System.alloc(layout)
} }
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.0.fetch_add(1, Ordering::SeqCst); self.0.fetch_add(1, Ordering::SeqCst);
System.dealloc(ptr, layout) System.dealloc(ptr, layout)
} }

View File

@ -11,11 +11,11 @@
// aux-build:helper.rs // aux-build:helper.rs
// no-prefer-dynamic // no-prefer-dynamic
#![feature(global_allocator, heap_api, allocator_api)] #![feature(allocator_api)]
extern crate helper; extern crate helper;
use std::alloc::{self, Global, Alloc, System, Layout, Opaque}; use std::alloc::{self, Global, Alloc, System, Layout};
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
static HITS: AtomicUsize = ATOMIC_USIZE_INIT; static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
@ -23,12 +23,12 @@ static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
struct A; struct A;
unsafe impl alloc::GlobalAlloc for A { unsafe impl alloc::GlobalAlloc for A {
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
HITS.fetch_add(1, Ordering::SeqCst); HITS.fetch_add(1, Ordering::SeqCst);
System.alloc(layout) System.alloc(layout)
} }
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
HITS.fetch_add(1, Ordering::SeqCst); HITS.fetch_add(1, Ordering::SeqCst);
System.dealloc(ptr, layout) System.dealloc(ptr, layout)
} }

View File

@ -12,7 +12,7 @@
// aux-build:helper.rs // aux-build:helper.rs
// no-prefer-dynamic // no-prefer-dynamic
#![feature(global_allocator, heap_api, allocator_api)] #![feature(allocator_api)]
extern crate custom; extern crate custom;
extern crate helper; extern crate helper;

View File

@ -19,7 +19,7 @@ extern crate custom;
extern crate custom_as_global; extern crate custom_as_global;
extern crate helper; extern crate helper;
use std::alloc::{Global, Alloc, GlobalAlloc, System, Layout}; use std::alloc::{alloc, dealloc, GlobalAlloc, System, Layout};
use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT); static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
@ -30,10 +30,10 @@ fn main() {
let layout = Layout::from_size_align(4, 2).unwrap(); let layout = Layout::from_size_align(4, 2).unwrap();
// Global allocator routes to the `custom_as_global` global // Global allocator routes to the `custom_as_global` global
let ptr = Global.alloc(layout.clone()); let ptr = alloc(layout.clone());
helper::work_with(&ptr); helper::work_with(&ptr);
assert_eq!(custom_as_global::get(), n + 1); assert_eq!(custom_as_global::get(), n + 1);
Global.dealloc(ptr, layout.clone()); dealloc(ptr, layout.clone());
assert_eq!(custom_as_global::get(), n + 2); assert_eq!(custom_as_global::get(), n + 2);
// Usage of the system allocator avoids all globals // Usage of the system allocator avoids all globals

View File

@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool {
println!("deallocate({:?}, {:?}", ptr, layout); println!("deallocate({:?}, {:?}", ptr, layout);
} }
Global.dealloc(NonNull::new_unchecked(ptr).as_opaque(), layout); Global.dealloc(NonNull::new_unchecked(ptr), layout);
} }
unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 {
@ -72,7 +72,7 @@ unsafe fn test_triangle() -> bool {
println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new);
} }
let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old, new.size()) let ret = Global.realloc(NonNull::new_unchecked(ptr), old, new.size())
.unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align()))); .unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align())));
if PRINT { if PRINT {

View File

@ -11,8 +11,6 @@
// compile-flags: -Z thinlto -C codegen-units=2 // compile-flags: -Z thinlto -C codegen-units=2
// min-llvm-version 4.0 // min-llvm-version 4.0
#![feature(allocator_api, global_allocator)]
#[global_allocator] #[global_allocator]
static A: std::alloc::System = std::alloc::System; static A: std::alloc::System = std::alloc::System;

View File

@ -1,14 +0,0 @@
// Copyright 2016 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.
#[global_allocator] //~ ERROR: attribute is an experimental feature
static A: usize = 0;
fn main() {}

View File

@ -1,11 +0,0 @@
error[E0658]: the `#[global_allocator]` attribute is an experimental feature (see issue #27389)
--> $DIR/feature-gate-global_allocator.rs:11:1
|
LL | #[global_allocator] //~ ERROR: attribute is an experimental feature
| ^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(global_allocator)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.