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:
commit
4367e41ea2
|
@ -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.
|
|
|
@ -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
|
|
|
@ -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.io’s `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() {}
|
|
||||||
```
|
|
|
@ -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` crate’s 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` crate’s 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` crate’s 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` crate’s 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` crate’s 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)]
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>>(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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 system’s 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 library’s 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 C’s `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 library’s 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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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]` \
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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() {}
|
|
|
@ -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`.
|
|
Loading…
Reference in New Issue