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
// except according to those terms.
#![unstable(feature = "allocator_api",
reason = "the precise API and guarantees it provides may be tweaked \
slightly, especially to possibly take into account the \
types being stored to make room for a future \
tracing garbage collector",
issue = "32838")]
//! Memory allocation APIs
#![stable(feature = "alloc_module", since = "1.28.0")]
use core::intrinsics::{min_align_of_val, size_of_val};
use core::ptr::{NonNull, Unique};
use core::usize;
#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use core::alloc::*;
@ -37,67 +35,112 @@ extern "Rust" {
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)]
pub struct Global;
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")]
pub type Heap = Global;
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")]
#[allow(non_upper_case_globals)]
pub const Heap: Global = Global;
unsafe impl GlobalAlloc for Global {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
let ptr = __rust_alloc(layout.size(), layout.align());
ptr as *mut Opaque
}
#[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
}
/// Allocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::alloc`] 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` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::alloc`].
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
__rust_alloc(layout.size(), layout.align())
}
/// 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 {
#[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
NonNull::new(alloc(layout)).ok_or(AllocErr)
}
#[inline]
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
dealloc(ptr.as_ptr(), layout)
}
#[inline]
unsafe fn realloc(&mut self,
ptr: NonNull<Opaque>,
ptr: NonNull<u8>,
layout: Layout,
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]
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, 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
} else {
let layout = Layout::from_size_align_unchecked(size, align);
let ptr = Global.alloc(layout);
let ptr = alloc(layout);
if !ptr.is_null() {
ptr as *mut u8
ptr
} else {
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.
if size != 0 {
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]
pub fn oom(layout: Layout) -> ! {
#[allow(improper_ctypes)]

View File

@ -519,7 +519,7 @@ impl<T: ?Sized> Arc<T> {
if self.inner().weak.fetch_sub(1, Release) == 1 {
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);
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 {
atomic::fence(Acquire);
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();
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());
let node = self.node;
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
}
}
@ -499,7 +499,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
> {
let node = self.node;
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
}
}
@ -1321,12 +1321,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
}
Global.dealloc(
right_node.node.as_opaque(),
right_node.node.cast(),
Layout::new::<InternalNode<K, V>>(),
);
} else {
Global.dealloc(
right_node.node.as_opaque(),
right_node.node.cast(),
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;
#[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",
reason = "futures in libcore are unstable",
issue = "50547")]
pub mod task;
// Primitive types using the heaps above
// 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
let ptr = if alloc_size == 0 {
NonNull::<T>::dangling().as_opaque()
NonNull::<T>::dangling()
} else {
let align = mem::align_of::<T>();
let layout = Layout::from_size_align(alloc_size, align).unwrap();
@ -103,13 +103,13 @@ impl<T, A: Alloc> RawVec<T, A> {
a.alloc(layout)
};
match result {
Ok(ptr) => ptr,
Ok(ptr) => ptr.cast(),
Err(_) => oom(layout),
}
};
RawVec {
ptr: ptr.cast().into(),
ptr: ptr.into(),
cap,
a,
}
@ -314,7 +314,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let new_cap = 2 * self.cap;
let new_size = new_cap * elem_size;
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,
new_size);
match ptr_res {
@ -373,7 +373,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let new_cap = 2 * self.cap;
let new_size = new_cap * elem_size;
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(_) => {
// We can't directly divide `size`.
self.cap = new_cap;
@ -546,7 +546,7 @@ impl<T, A: Alloc> RawVec<T, A> {
// FIXME: may crash and burn on over-reserve
alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow());
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(_) => {
self.cap = new_cap;
@ -607,7 +607,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let new_size = elem_size * amount;
let align = mem::align_of::<T>();
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,
new_size) {
Ok(p) => self.ptr = p.cast().into(),
@ -667,7 +667,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let res = match self.current_layout() {
Some(layout) => {
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),
};
@ -710,7 +710,7 @@ impl<T, A: Alloc> RawVec<T, A> {
let elem_size = mem::size_of::<T>();
if elem_size != 0 {
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)]
mod tests {
use super::*;
use alloc::Opaque;
#[test]
fn allocator_param() {
@ -773,7 +772,7 @@ mod tests {
// before allocation attempts start failing.
struct BoundedAlloc { fuel: usize }
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();
if size > self.fuel {
return Err(AllocErr);
@ -783,7 +782,7 @@ mod tests {
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)
}
}

View File

@ -259,7 +259,7 @@ use core::ops::CoerceUnsized;
use core::ptr::{self, NonNull};
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 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
// into the new RcBox will be dropped, then the memory freed.
struct Guard<T> {
mem: NonNull<Opaque>,
mem: NonNull<u8>,
elems: *mut T,
layout: Layout,
n_elems: usize,
@ -755,7 +755,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
let v_ptr = v as *const [T];
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);
// Pointer to first element
@ -839,7 +839,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
self.dec_weak();
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 strong pointers have disappeared.
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]
#![allow(unused_attributes)]
#![unstable(feature = "alloc_jemalloc",
reason = "this library is unlikely to be stabilized in its current \
form or name",
issue = "27783")]
reason = "implementation detail of std, does not provide any public API",
issue = "0")]
#![feature(core_intrinsics)]
#![feature(libc)]
#![feature(linkage)]

View File

@ -14,7 +14,6 @@
reason = "this library is unlikely to be stabilized in its current \
form or name",
issue = "32838")]
#![feature(global_allocator)]
#![feature(allocator_api)]
#![feature(core_intrinsics)]
#![feature(staged_api)]
@ -41,54 +40,78 @@ const MIN_ALIGN: usize = 8;
#[allow(dead_code)]
const MIN_ALIGN: usize = 16;
use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque};
use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout};
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;
#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for System {
#[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)
}
#[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)
}
#[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)
}
#[inline]
unsafe fn realloc(&mut self,
ptr: NonNull<Opaque>,
ptr: NonNull<u8>,
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)
}
}
#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
mod realloc_fallback {
use core::alloc::{GlobalAlloc, Opaque, Layout};
use core::alloc::{GlobalAlloc, Layout};
use core::cmp;
use core::ptr;
impl super::System {
pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout,
new_size: usize) -> *mut Opaque {
pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
new_size: usize) -> *mut u8 {
// Docs for GlobalAlloc::realloc require this to be valid:
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
let new_ptr = GlobalAlloc::alloc(self, new_layout);
if !new_ptr.is_null() {
let size = cmp::min(old_layout.size(), new_size);
ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size);
ptr::copy_nonoverlapping(ptr, new_ptr, size);
GlobalAlloc::dealloc(self, ptr, old_layout);
}
new_ptr
@ -104,21 +127,19 @@ mod platform {
use MIN_ALIGN;
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 {
#[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() {
libc::malloc(layout.size()) as *mut Opaque
libc::malloc(layout.size()) as *mut u8
} else {
#[cfg(target_os = "macos")]
{
if layout.align() > (1 << 31) {
// FIXME: use Opaque::null_mut
// https://github.com/rust-lang/rust/issues/49659
return 0 as *mut Opaque
return ptr::null_mut()
}
}
aligned_malloc(&layout)
@ -126,27 +147,27 @@ mod platform {
}
#[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() {
libc::calloc(layout.size(), 1) as *mut Opaque
libc::calloc(layout.size(), 1) as *mut u8
} else {
let ptr = self.alloc(layout.clone());
if !ptr.is_null() {
ptr::write_bytes(ptr as *mut u8, 0, layout.size());
ptr::write_bytes(ptr, 0, layout.size());
}
ptr
}
}
#[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)
}
#[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 {
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 {
self.realloc_fallback(ptr, layout, new_size)
}
@ -155,7 +176,7 @@ mod platform {
#[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))]
#[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
// doesn't have the `posix_memalign` API used below. Instead we use
// `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
// [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
// /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")))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque {
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
let mut out = ptr::null_mut();
let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
if ret != 0 {
// FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659
0 as *mut Opaque
ptr::null_mut()
} else {
out as *mut Opaque
out as *mut u8
}
}
}
@ -195,7 +215,7 @@ mod platform {
mod platform {
use MIN_ALIGN;
use System;
use core::alloc::{GlobalAlloc, Opaque, Layout};
use core::alloc::{GlobalAlloc, Layout};
type LPVOID = *mut u8;
type HANDLE = LPVOID;
@ -227,7 +247,7 @@ mod platform {
}
#[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 {
HeapAlloc(GetProcessHeap(), flags, layout.size())
} else {
@ -239,29 +259,29 @@ mod platform {
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 {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
allocate_with_flags(layout, 0)
}
#[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)
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if layout.align() <= MIN_ALIGN {
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}",
GetLastError());
} else {
let header = get_header(ptr as *mut u8);
let header = get_header(ptr);
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
debug_assert!(err != 0, "Failed to free heap memory: {}",
GetLastError());
@ -269,9 +289,9 @@ mod platform {
}
#[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 {
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
} else {
self.realloc_fallback(ptr, layout, new_size)
}
@ -300,32 +320,32 @@ mod platform {
mod platform {
extern crate dlmalloc;
use core::alloc::{GlobalAlloc, Layout, Opaque};
use core::alloc::{GlobalAlloc, Layout};
use System;
// No need for synchronization here as wasm is currently single-threaded
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 {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
DLMALLOC.malloc(layout.size(), layout.align())
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
DLMALLOC.calloc(layout.size(), layout.align())
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align())
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
DLMALLOC.free(ptr, layout.size(), layout.align())
}
#[inline]
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
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
// except according to those terms.
#![unstable(feature = "allocator_api",
reason = "the precise API and guarantees it provides may be tweaked \
slightly, especially to possibly take into account the \
types being stored to make room for a future \
tracing garbage collector",
issue = "32838")]
//! Memory allocation APIs
#![stable(feature = "alloc_module", since = "1.28.0")]
use cmp;
use fmt;
@ -22,30 +19,15 @@ use usize;
use ptr::{self, NonNull};
use num::NonZeroUsize;
extern {
/// An opaque, unsized type. Used for pointers to allocated memory.
///
/// 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 _
}
}
#[unstable(feature = "alloc_internals", issue = "0")]
#[cfg(stage0)]
pub type Opaque = u8;
/// Represents the combination of a starting address and
/// a total capacity of the returned block.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Debug)]
pub struct Excess(pub NonNull<Opaque>, pub usize);
pub struct Excess(pub NonNull<u8>, pub usize);
fn size_align<T>() -> (usize, usize) {
(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`
/// method must either ensure that conditions like this are met, or
/// use specific allocators with looser requirements.)
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Layout {
// 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`,
/// must not overflow (i.e. the rounded value must be less than
/// `usize::MAX`).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline]
pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
if !align.is_power_of_two() {
@ -124,20 +108,24 @@ impl Layout {
///
/// This function is unsafe as it does not verify the preconditions from
/// [`Layout::from_size_align`](#method.from_size_align).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline]
pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
}
/// The minimum size in bytes for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline]
pub fn size(&self) -> usize { self.size_ }
/// The minimum byte alignment for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline]
pub fn align(&self) -> usize { self.align_.get() }
/// Constructs a `Layout` suitable for holding a value of type `T`.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline]
pub fn new<T>() -> Self {
let (size, align) = size_align::<T>();
@ -154,6 +142,7 @@ impl Layout {
/// Produces layout describing a record that could be used to
/// allocate backing structure for `T` (which could be a trait
/// or other unsized type like a slice).
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Self {
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`
/// violates the conditions listed in
/// [`Layout::from_size_align`](#method.from_size_align).
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub fn align_to(&self, align: usize) -> Self {
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
/// address for the whole allocated block of memory. One way to
/// satisfy this constraint is to ensure `align <= self.align()`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub fn padding_needed_for(&self, align: usize) -> usize {
let len = self.size();
@ -238,6 +229,7 @@ impl Layout {
/// of each element in the array.
///
/// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
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).
///
/// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
let new_align = cmp::max(self.align(), next.align());
@ -289,6 +282,7 @@ impl Layout {
/// aligned.
///
/// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
@ -310,6 +304,7 @@ impl Layout {
/// `extend`.)
///
/// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
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]`.
///
/// On arithmetic overflow, returns `LayoutErr`.
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
Layout::new::<T>()
@ -332,28 +328,33 @@ impl Layout {
}
}
/// The parameters given to `Layout::from_size_align` do not satisfy
/// its documented constraints.
/// The parameters given to `Layout::from_size_align`
/// or some other `Layout` constructor
/// do not satisfy its documented constraints.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutErr {
private: ()
}
// (we need this for downstream impl of trait Error)
#[stable(feature = "alloc_layout", since = "1.28.0")]
impl fmt::Display for LayoutErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("invalid parameters to Layout::from_size_align")
}
}
/// The `AllocErr` error specifies whether an allocation failure is
/// specifically due to resource exhaustion or if it is due to
/// The `AllocErr` error indicates an allocation failure
/// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this
/// allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr;
// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocErr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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
/// `shrink_in_place` were unable to reuse the given memory block for
/// a requested layout.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct CannotReallocInPlace;
#[unstable(feature = "allocator_api", issue = "32838")]
impl CannotReallocInPlace {
pub fn description(&self) -> &str {
"cannot reallocate allocator's memory in place"
@ -373,6 +376,7 @@ impl CannotReallocInPlace {
}
// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for CannotReallocInPlace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
@ -380,6 +384,7 @@ impl fmt::Display for CannotReallocInPlace {
}
/// Augments `AllocErr` with a CapacityOverflow variant.
// FIXME: should this be in libcore or liballoc?
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
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.
///
/// 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 {
/// Allocate memory as described by the given `layout`.
///
/// Returns a pointer to newly-allocated memory,
/// or NULL to indicate allocation failure.
/// or null to indicate allocation failure.
///
/// # Safety
///
/// **FIXME:** what are the exact requirements?
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque;
/// This function is unsafe because undefined behavior can result
/// 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`.
///
/// # Safety
///
/// **FIXME:** what are the exact requirements?
/// In particular around layout *fit*. (See docs for the `Alloc` trait.)
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout);
/// This function is unsafe because undefined behavior can result
/// if the caller does not ensure all of the following:
///
/// * `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 ptr = self.alloc(layout);
if !ptr.is_null() {
ptr::write_bytes(ptr as *mut u8, 0, size);
ptr::write_bytes(ptr, 0, size);
}
ptr
}
@ -439,26 +546,61 @@ pub unsafe trait GlobalAlloc {
/// Shink or grow a block of memory to the given `new_size`.
/// 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`),
/// or NULL to indicate reallocation failure.
/// If this returns a non-null pointer, then ownership of the memory block
/// 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
/// to have been deallocated.
/// If this method returns null, then ownership of the memory
/// block has not been transferred to this allocator, and the
/// contents of the memory block are unaltered.
///
/// # Safety
///
/// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`,
/// must not overflow (i.e. the rounded value must be less than `usize::MAX`).
/// This function is unsafe because undefined behavior can result
/// if the caller does not ensure all of the following:
///
/// **FIXME:** what are the exact requirements?
/// In particular around layout *fit*. (See docs for the `Alloc` trait.)
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
/// * `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`).
///
/// (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.)
///
/// # 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_ptr = self.alloc(new_layout);
if !new_ptr.is_null() {
ptr::copy_nonoverlapping(
ptr as *const u8,
new_ptr as *mut u8,
ptr,
new_ptr,
cmp::min(layout.size(), new_size),
);
self.dealloc(ptr, layout);
@ -540,27 +682,22 @@ pub unsafe trait GlobalAlloc {
/// retain their validity until at least the instance of `Alloc` is dropped
/// 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
/// this trait are allowed to rely on the contracts defined on each method,
/// and implementors must ensure such contracts remain true.
///
/// Note that this list may get tweaked over time as clarifications are made in
/// the future. Additionally global allocators may gain unique requirements for
/// how to safely implement one in the future as well.
/// the future.
#[unstable(feature = "allocator_api", issue = "32838")]
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 ;
// e.g. in C, `malloc` of 0 will either return a null pointer or a
// unique pointer, but will not have arbitrary undefined
// behavior. Rust should consider revising the alloc::heap crate
// to reflect this reality.)
// behavior.
// However in jemalloc for example,
// `mallocx(0)` is documented as undefined behavior.)
/// Returns a pointer meeting the size and alignment guarantees of
/// `layout`.
@ -596,9 +733,11 @@ pub unsafe trait Alloc {
/// library that aborts on memory exhaustion.)
///
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr>;
/// allocation error are encouraged to call the [`oom`] function,
/// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr>;
/// Deallocate the memory referenced by `ptr`.
///
@ -615,7 +754,7 @@ pub unsafe trait Alloc {
/// * In addition to fitting the block of memory `layout`, the
/// alignment of the `layout` must match the alignment used
/// 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 ==
// usable_size
@ -703,13 +842,15 @@ pub unsafe trait Alloc {
/// implement this trait atop an underlying native allocation
/// library that aborts on memory exhaustion.)
///
/// Clients wishing to abort computation in response to an
/// reallocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
/// 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
unsafe fn realloc(&mut self,
ptr: NonNull<Opaque>,
ptr: NonNull<u8>,
layout: Layout,
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
new_size: usize) -> Result<NonNull<u8>, AllocErr> {
let old_size = layout.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 result = self.alloc(new_layout);
if let Ok(new_ptr) = result {
ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8,
new_ptr.as_ptr() as *mut u8,
ptr::copy_nonoverlapping(ptr.as_ptr(),
new_ptr.as_ptr(),
cmp::min(old_size, new_size));
self.dealloc(ptr, layout);
}
@ -748,13 +889,15 @@ pub unsafe trait Alloc {
/// constraints, just as in `alloc`.
///
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
/// allocation error are encouraged to call the [`oom`] function,
/// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
let size = layout.size();
let p = self.alloc(layout);
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
}
@ -774,8 +917,10 @@ pub unsafe trait Alloc {
/// constraints, just as in `alloc`.
///
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
/// allocation error are encouraged to call the [`oom`] function,
/// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
let usable_size = self.usable_size(&layout);
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
/// constraints, just as in `realloc`.
///
/// Clients wishing to abort computation in response to an
/// reallocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
/// 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
unsafe fn realloc_excess(&mut self,
ptr: NonNull<Opaque>,
ptr: NonNull<u8>,
layout: Layout,
new_size: usize) -> Result<Excess, AllocErr> {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
@ -840,11 +987,11 @@ pub unsafe trait Alloc {
/// could fit `layout`.
///
/// 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
/// another reallocation method before resorting to an abort.
unsafe fn grow_in_place(&mut self,
ptr: NonNull<Opaque>,
ptr: NonNull<u8>,
layout: Layout,
new_size: usize) -> Result<(), CannotReallocInPlace> {
let _ = ptr; // this default implementation doesn't care about the actual address.
@ -895,11 +1042,11 @@ pub unsafe trait Alloc {
/// could fit `layout`.
///
/// 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
/// on another reallocation method before resorting to an abort.
unsafe fn shrink_in_place(&mut self,
ptr: NonNull<Opaque>,
ptr: NonNull<u8>,
layout: Layout,
new_size: usize) -> Result<(), CannotReallocInPlace> {
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.
///
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
/// allocation error are encouraged to call the [`oom`] function,
/// rather than directly invoking `panic!` or similar.
///
/// [`oom`]: ../../alloc/alloc/fn.oom.html
fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr>
where Self: Sized
{
@ -978,7 +1127,7 @@ pub unsafe trait Alloc {
{
let k = Layout::new::<T>();
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.
///
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
/// allocation error are encouraged to call the [`oom`] function,
/// 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>
where Self: Sized
{
@ -1054,9 +1205,11 @@ pub unsafe trait Alloc {
///
/// Always returns `Err` on arithmetic overflow.
///
/// Clients wishing to abort computation in response to an
/// reallocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
/// 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
unsafe fn realloc_array<T>(&mut self,
ptr: NonNull<T>,
n_old: usize,
@ -1066,7 +1219,7 @@ pub unsafe trait Alloc {
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 => {
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)
@ -1099,7 +1252,7 @@ pub unsafe trait Alloc {
{
match Layout::array::<T>(n) {
Ok(ref k) if k.size() > 0 => {
Ok(self.dealloc(ptr.as_opaque(), k.clone()))
Ok(self.dealloc(ptr.cast(), k.clone()))
}
_ => {
Err(AllocErr)

View File

@ -215,13 +215,6 @@ pub mod task;
#[allow(missing_docs)]
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
mod iter_private;
mod nonzero;

View File

@ -2922,14 +2922,6 @@ impl<T: ?Sized> NonNull<T> {
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")]

View File

@ -237,7 +237,7 @@ impl<'a> AllocFnFactory<'a> {
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
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 => {
@ -281,17 +281,4 @@ impl<'a> AllocFnFactory<'a> {
let ty_u8 = self.cx.ty_path(u8);
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]
#![feature(alloc_system)]
#![feature(allocator_api)]
#![feature(global_allocator)]
#![cfg_attr(stage0, feature(global_allocator))]
#![feature(sanitizer_runtime)]
#![feature(staged_api)]
#![no_std]

View File

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

View File

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

View File

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

View File

@ -8,19 +8,84 @@
// option. This file may not be copied, modified, or distributed
// 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")]
#[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::*;
#![stable(feature = "alloc_module", since = "1.28.0")]
use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};
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());
/// 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.
///
/// The OOM hook is a global resource.
#[unstable(feature = "oom_hook", issue = "51245")]
pub fn set_oom_hook(hook: fn(Layout)) {
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`].*
///
/// 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) {
let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
if hook.is_null() {
@ -59,6 +126,7 @@ fn default_oom_hook(layout: Layout) {
#[cfg(not(test))]
#[doc(hidden)]
#[lang = "oom"]
#[unstable(feature = "alloc_internals", issue = "0")]
pub extern fn rust_oom(layout: Layout) -> ! {
let hook = HOOK.load(Ordering::SeqCst);
let hook: fn(Layout) = if hook.is_null() {
@ -73,8 +141,9 @@ pub extern fn rust_oom(layout: Layout) -> ! {
#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "0")]
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 signatures src/librustc_allocator/lib.rs
@ -85,7 +154,7 @@ pub mod __default_lib_allocator {
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size, align);
System.alloc(layout) as *mut u8
System.alloc(layout)
}
#[no_mangle]
@ -93,7 +162,7 @@ pub mod __default_lib_allocator {
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
size: 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]
@ -103,13 +172,13 @@ pub mod __default_lib_allocator {
align: usize,
new_size: usize) -> *mut u8 {
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]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
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())
.unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
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
// 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;
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub use heap::CollectionAllocErr;
pub use alloc::CollectionAllocErr;
mod hash;

View File

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

View File

@ -264,7 +264,6 @@
#![feature(fnbox)]
#![feature(futures_api)]
#![feature(hashmap_internals)]
#![feature(heap_api)]
#![feature(int_error_internals)]
#![feature(integer_atomics)]
#![feature(into_cow)]
@ -500,13 +499,6 @@ pub mod process;
pub mod sync;
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
#[macro_use]
mod sys_common;

View File

@ -357,8 +357,6 @@ declare_features! (
// Trait aliases
(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
(active, allocator_internals, "1.20.0", None, None),
@ -615,6 +613,8 @@ declare_features! (
(accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
// Termination trait in tests (RFC 1937)
(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
@ -776,11 +776,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
"the `#[rustc_const_unstable]` attribute \
is an internal feature",
cfg_fn!(rustc_const_unstable))),
("global_allocator", Normal, Gated(Stability::Unstable,
"global_allocator",
"the `#[global_allocator]` attribute is \
an experimental feature",
cfg_fn!(global_allocator))),
("global_allocator", Normal, Ungated),
("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
"allocator_internals",
"the `#[default_lib_allocator]` \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,6 +18,11 @@
mod cross_crate {
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::*;
pub fn foo() {
@ -73,6 +78,8 @@ mod cross_crate {
// the patterns are all fine:
{ .. } = 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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,18 +13,18 @@
#![feature(heap_api, allocator_api)]
#![crate_type = "rlib"]
use std::alloc::{GlobalAlloc, System, Layout, Opaque};
use std::alloc::{GlobalAlloc, System, Layout};
use std::sync::atomic::{AtomicUsize, Ordering};
pub struct A(pub AtomicUsize);
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);
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);
System.dealloc(ptr, layout)
}

View File

@ -11,11 +11,11 @@
// aux-build:helper.rs
// no-prefer-dynamic
#![feature(global_allocator, heap_api, allocator_api)]
#![feature(allocator_api)]
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};
static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
@ -23,12 +23,12 @@ static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
struct 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);
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);
System.dealloc(ptr, layout)
}

View File

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

View File

@ -19,7 +19,7 @@ extern crate custom;
extern crate custom_as_global;
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};
static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
@ -30,10 +30,10 @@ fn main() {
let layout = Layout::from_size_align(4, 2).unwrap();
// Global allocator routes to the `custom_as_global` global
let ptr = Global.alloc(layout.clone());
let ptr = alloc(layout.clone());
helper::work_with(&ptr);
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);
// Usage of the system allocator avoids all globals

View File

@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool {
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 {
@ -72,7 +72,7 @@ unsafe fn test_triangle() -> bool {
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())));
if PRINT {

View File

@ -11,8 +11,6 @@
// compile-flags: -Z thinlto -C codegen-units=2
// min-llvm-version 4.0
#![feature(allocator_api, global_allocator)]
#[global_allocator]
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`.