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
|
||||
// except according to those terms.
|
||||
|
||||
#![unstable(feature = "allocator_api",
|
||||
reason = "the precise API and guarantees it provides may be tweaked \
|
||||
slightly, especially to possibly take into account the \
|
||||
types being stored to make room for a future \
|
||||
tracing garbage collector",
|
||||
issue = "32838")]
|
||||
//! Memory allocation APIs
|
||||
|
||||
#![stable(feature = "alloc_module", since = "1.28.0")]
|
||||
|
||||
use core::intrinsics::{min_align_of_val, size_of_val};
|
||||
use core::ptr::{NonNull, Unique};
|
||||
use core::usize;
|
||||
|
||||
#[stable(feature = "alloc_module", since = "1.28.0")]
|
||||
#[doc(inline)]
|
||||
pub use core::alloc::*;
|
||||
|
||||
@ -37,67 +35,112 @@ extern "Rust" {
|
||||
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
|
||||
}
|
||||
|
||||
/// The global memory allocator.
|
||||
///
|
||||
/// This type implements the [`Alloc`] trait by forwarding calls
|
||||
/// to the allocator registered with the `#[global_allocator]` attribute
|
||||
/// if there is one, or the `std` crate’s default.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct Global;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")]
|
||||
pub type Heap = Global;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const Heap: Global = Global;
|
||||
|
||||
unsafe impl GlobalAlloc for Global {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
|
||||
let ptr = __rust_alloc(layout.size(), layout.align());
|
||||
ptr as *mut Opaque
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
|
||||
__rust_dealloc(ptr as *mut u8, layout.size(), layout.align())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
|
||||
let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size);
|
||||
ptr as *mut Opaque
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
|
||||
let ptr = __rust_alloc_zeroed(layout.size(), layout.align());
|
||||
ptr as *mut Opaque
|
||||
}
|
||||
/// Allocate memory with the global allocator.
|
||||
///
|
||||
/// This function forwards calls to the [`GlobalAlloc::alloc`] method
|
||||
/// of the allocator registered with the `#[global_allocator]` attribute
|
||||
/// if there is one, or the `std` crate’s default.
|
||||
///
|
||||
/// This function is expected to be deprecated in favor of the `alloc` method
|
||||
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See [`GlobalAlloc::alloc`].
|
||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
|
||||
__rust_alloc(layout.size(), layout.align())
|
||||
}
|
||||
|
||||
/// Deallocate memory with the global allocator.
|
||||
///
|
||||
/// This function forwards calls to the [`GlobalAlloc::dealloc`] method
|
||||
/// of the allocator registered with the `#[global_allocator]` attribute
|
||||
/// if there is one, or the `std` 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 {
|
||||
#[inline]
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
|
||||
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
|
||||
NonNull::new(alloc(layout)).ok_or(AllocErr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
|
||||
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
|
||||
dealloc(ptr.as_ptr(), layout)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&mut self,
|
||||
ptr: NonNull<Opaque>,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
new_size: usize)
|
||||
-> Result<NonNull<Opaque>, AllocErr>
|
||||
-> Result<NonNull<u8>, AllocErr>
|
||||
{
|
||||
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
|
||||
NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
|
||||
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
|
||||
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
|
||||
NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,9 +154,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
||||
align as *mut u8
|
||||
} else {
|
||||
let layout = Layout::from_size_align_unchecked(size, align);
|
||||
let ptr = Global.alloc(layout);
|
||||
let ptr = alloc(layout);
|
||||
if !ptr.is_null() {
|
||||
ptr as *mut u8
|
||||
ptr
|
||||
} else {
|
||||
oom(layout)
|
||||
}
|
||||
@ -129,10 +172,23 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
|
||||
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
|
||||
if size != 0 {
|
||||
let layout = Layout::from_size_align_unchecked(size, align);
|
||||
Global.dealloc(ptr as *mut Opaque, layout);
|
||||
dealloc(ptr as *mut u8, layout);
|
||||
}
|
||||
}
|
||||
|
||||
/// Abort on memory allocation error or failure.
|
||||
///
|
||||
/// Callers of memory allocation APIs wishing to abort computation
|
||||
/// in response to an allocation error are encouraged to call this function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// The default behavior of this function is to print a message to standard error
|
||||
/// and abort the process.
|
||||
/// It can be replaced with [`set_oom_hook`] and [`take_oom_hook`].
|
||||
///
|
||||
/// [`set_oom_hook`]: ../../std/alloc/fn.set_oom_hook.html
|
||||
/// [`take_oom_hook`]: ../../std/alloc/fn.take_oom_hook.html
|
||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||
#[rustc_allocator_nounwind]
|
||||
pub fn oom(layout: Layout) -> ! {
|
||||
#[allow(improper_ctypes)]
|
||||
|
@ -519,7 +519,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
|
||||
if self.inner().weak.fetch_sub(1, Release) == 1 {
|
||||
atomic::fence(Acquire);
|
||||
Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref()))
|
||||
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -639,7 +639,7 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
|
||||
let slice = from_raw_parts_mut(self.elems, self.n_elems);
|
||||
ptr::drop_in_place(slice);
|
||||
|
||||
Global.dealloc(self.mem.as_opaque(), self.layout.clone());
|
||||
Global.dealloc(self.mem.cast(), self.layout.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1196,7 +1196,7 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||
if self.inner().weak.fetch_sub(1, Release) == 1 {
|
||||
atomic::fence(Acquire);
|
||||
unsafe {
|
||||
Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref()))
|
||||
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ impl<K, V> Root<K, V> {
|
||||
self.as_mut().as_leaf_mut().parent = ptr::null();
|
||||
|
||||
unsafe {
|
||||
Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::<InternalNode<K, V>>());
|
||||
Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -478,7 +478,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
|
||||
debug_assert!(!self.is_shared_root());
|
||||
let node = self.node;
|
||||
let ret = self.ascend().ok();
|
||||
Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>());
|
||||
Global.dealloc(node.cast(), Layout::new::<LeafNode<K, V>>());
|
||||
ret
|
||||
}
|
||||
}
|
||||
@ -499,7 +499,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
|
||||
> {
|
||||
let node = self.node;
|
||||
let ret = self.ascend().ok();
|
||||
Global.dealloc(node.as_opaque(), Layout::new::<InternalNode<K, V>>());
|
||||
Global.dealloc(node.cast(), Layout::new::<InternalNode<K, V>>());
|
||||
ret
|
||||
}
|
||||
}
|
||||
@ -1321,12 +1321,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
|
||||
}
|
||||
|
||||
Global.dealloc(
|
||||
right_node.node.as_opaque(),
|
||||
right_node.node.cast(),
|
||||
Layout::new::<InternalNode<K, V>>(),
|
||||
);
|
||||
} else {
|
||||
Global.dealloc(
|
||||
right_node.node.as_opaque(),
|
||||
right_node.node.cast(),
|
||||
Layout::new::<LeafNode<K, V>>(),
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
|
||||
/// Use the `alloc` module instead.
|
||||
pub mod heap {
|
||||
pub use alloc::*;
|
||||
}
|
||||
|
||||
#[unstable(feature = "futures_api",
|
||||
reason = "futures in libcore are unstable",
|
||||
issue = "50547")]
|
||||
pub mod task;
|
||||
|
||||
// Primitive types using the heaps above
|
||||
|
||||
// Need to conditionally define the mod from `boxed.rs` to avoid
|
||||
|
@ -93,7 +93,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
|
||||
// handles ZSTs and `cap = 0` alike
|
||||
let ptr = if alloc_size == 0 {
|
||||
NonNull::<T>::dangling().as_opaque()
|
||||
NonNull::<T>::dangling()
|
||||
} else {
|
||||
let align = mem::align_of::<T>();
|
||||
let layout = Layout::from_size_align(alloc_size, align).unwrap();
|
||||
@ -103,13 +103,13 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
a.alloc(layout)
|
||||
};
|
||||
match result {
|
||||
Ok(ptr) => ptr,
|
||||
Ok(ptr) => ptr.cast(),
|
||||
Err(_) => oom(layout),
|
||||
}
|
||||
};
|
||||
|
||||
RawVec {
|
||||
ptr: ptr.cast().into(),
|
||||
ptr: ptr.into(),
|
||||
cap,
|
||||
a,
|
||||
}
|
||||
@ -314,7 +314,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
let new_cap = 2 * self.cap;
|
||||
let new_size = new_cap * elem_size;
|
||||
alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
|
||||
let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(),
|
||||
let ptr_res = self.a.realloc(NonNull::from(self.ptr).cast(),
|
||||
cur,
|
||||
new_size);
|
||||
match ptr_res {
|
||||
@ -373,7 +373,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
let new_cap = 2 * self.cap;
|
||||
let new_size = new_cap * elem_size;
|
||||
alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
|
||||
match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) {
|
||||
match self.a.grow_in_place(NonNull::from(self.ptr).cast(), old_layout, new_size) {
|
||||
Ok(_) => {
|
||||
// We can't directly divide `size`.
|
||||
self.cap = new_cap;
|
||||
@ -546,7 +546,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
// FIXME: may crash and burn on over-reserve
|
||||
alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow());
|
||||
match self.a.grow_in_place(
|
||||
NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(),
|
||||
NonNull::from(self.ptr).cast(), old_layout, new_layout.size(),
|
||||
) {
|
||||
Ok(_) => {
|
||||
self.cap = new_cap;
|
||||
@ -607,7 +607,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
let new_size = elem_size * amount;
|
||||
let align = mem::align_of::<T>();
|
||||
let old_layout = Layout::from_size_align_unchecked(old_size, align);
|
||||
match self.a.realloc(NonNull::from(self.ptr).as_opaque(),
|
||||
match self.a.realloc(NonNull::from(self.ptr).cast(),
|
||||
old_layout,
|
||||
new_size) {
|
||||
Ok(p) => self.ptr = p.cast().into(),
|
||||
@ -667,7 +667,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
let res = match self.current_layout() {
|
||||
Some(layout) => {
|
||||
debug_assert!(new_layout.align() == layout.align());
|
||||
self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size())
|
||||
self.a.realloc(NonNull::from(self.ptr).cast(), layout, new_layout.size())
|
||||
}
|
||||
None => self.a.alloc(new_layout),
|
||||
};
|
||||
@ -710,7 +710,7 @@ impl<T, A: Alloc> RawVec<T, A> {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
if elem_size != 0 {
|
||||
if let Some(layout) = self.current_layout() {
|
||||
self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout);
|
||||
self.a.dealloc(NonNull::from(self.ptr).cast(), layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -753,7 +753,6 @@ fn capacity_overflow() -> ! {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloc::Opaque;
|
||||
|
||||
#[test]
|
||||
fn allocator_param() {
|
||||
@ -773,7 +772,7 @@ mod tests {
|
||||
// before allocation attempts start failing.
|
||||
struct BoundedAlloc { fuel: usize }
|
||||
unsafe impl Alloc for BoundedAlloc {
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
|
||||
let size = layout.size();
|
||||
if size > self.fuel {
|
||||
return Err(AllocErr);
|
||||
@ -783,7 +782,7 @@ mod tests {
|
||||
err @ Err(_) => err,
|
||||
}
|
||||
}
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
|
||||
Global.dealloc(ptr, layout)
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ use core::ops::CoerceUnsized;
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::convert::From;
|
||||
|
||||
use alloc::{Global, Alloc, Layout, Opaque, box_free, oom};
|
||||
use alloc::{Global, Alloc, Layout, box_free, oom};
|
||||
use string::String;
|
||||
use vec::Vec;
|
||||
|
||||
@ -732,7 +732,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
|
||||
// In the event of a panic, elements that have been written
|
||||
// into the new RcBox will be dropped, then the memory freed.
|
||||
struct Guard<T> {
|
||||
mem: NonNull<Opaque>,
|
||||
mem: NonNull<u8>,
|
||||
elems: *mut T,
|
||||
layout: Layout,
|
||||
n_elems: usize,
|
||||
@ -755,7 +755,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
|
||||
let v_ptr = v as *const [T];
|
||||
let ptr = Self::allocate_for_ptr(v_ptr);
|
||||
|
||||
let mem = ptr as *mut _ as *mut Opaque;
|
||||
let mem = ptr as *mut _ as *mut u8;
|
||||
let layout = Layout::for_value(&*ptr);
|
||||
|
||||
// Pointer to first element
|
||||
@ -839,7 +839,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
|
||||
self.dec_weak();
|
||||
|
||||
if self.weak() == 0 {
|
||||
Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref()));
|
||||
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1263,7 +1263,7 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||
// the weak count starts at 1, and will only go to zero if all
|
||||
// the strong pointers have disappeared.
|
||||
if self.weak() == 0 {
|
||||
Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref()));
|
||||
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,9 +11,8 @@
|
||||
#![no_std]
|
||||
#![allow(unused_attributes)]
|
||||
#![unstable(feature = "alloc_jemalloc",
|
||||
reason = "this library is unlikely to be stabilized in its current \
|
||||
form or name",
|
||||
issue = "27783")]
|
||||
reason = "implementation detail of std, does not provide any public API",
|
||||
issue = "0")]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(libc)]
|
||||
#![feature(linkage)]
|
||||
|
@ -14,7 +14,6 @@
|
||||
reason = "this library is unlikely to be stabilized in its current \
|
||||
form or name",
|
||||
issue = "32838")]
|
||||
#![feature(global_allocator)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(staged_api)]
|
||||
@ -41,54 +40,78 @@ const MIN_ALIGN: usize = 8;
|
||||
#[allow(dead_code)]
|
||||
const MIN_ALIGN: usize = 16;
|
||||
|
||||
use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque};
|
||||
use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
/// The default memory allocator provided by the operating system.
|
||||
///
|
||||
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
|
||||
/// plus related functions.
|
||||
///
|
||||
/// This type can be used in a `static` item
|
||||
/// with the `#[global_allocator]` attribute
|
||||
/// to force the global allocator to be the 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;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
unsafe impl Alloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
|
||||
NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
|
||||
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
|
||||
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
|
||||
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&mut self,
|
||||
ptr: NonNull<Opaque>,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
|
||||
new_size: usize) -> Result<NonNull<u8>, AllocErr> {
|
||||
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
|
||||
mod realloc_fallback {
|
||||
use core::alloc::{GlobalAlloc, Opaque, Layout};
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::cmp;
|
||||
use core::ptr;
|
||||
|
||||
impl super::System {
|
||||
pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout,
|
||||
new_size: usize) -> *mut Opaque {
|
||||
pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
|
||||
new_size: usize) -> *mut u8 {
|
||||
// Docs for GlobalAlloc::realloc require this to be valid:
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
|
||||
|
||||
let new_ptr = GlobalAlloc::alloc(self, new_layout);
|
||||
if !new_ptr.is_null() {
|
||||
let size = cmp::min(old_layout.size(), new_size);
|
||||
ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size);
|
||||
ptr::copy_nonoverlapping(ptr, new_ptr, size);
|
||||
GlobalAlloc::dealloc(self, ptr, old_layout);
|
||||
}
|
||||
new_ptr
|
||||
@ -104,21 +127,19 @@ mod platform {
|
||||
|
||||
use MIN_ALIGN;
|
||||
use System;
|
||||
use core::alloc::{GlobalAlloc, Layout, Opaque};
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
|
||||
libc::malloc(layout.size()) as *mut Opaque
|
||||
libc::malloc(layout.size()) as *mut u8
|
||||
} else {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if layout.align() > (1 << 31) {
|
||||
// FIXME: use Opaque::null_mut
|
||||
// https://github.com/rust-lang/rust/issues/49659
|
||||
return 0 as *mut Opaque
|
||||
return ptr::null_mut()
|
||||
}
|
||||
}
|
||||
aligned_malloc(&layout)
|
||||
@ -126,27 +147,27 @@ mod platform {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
|
||||
libc::calloc(layout.size(), 1) as *mut Opaque
|
||||
libc::calloc(layout.size(), 1) as *mut u8
|
||||
} else {
|
||||
let ptr = self.alloc(layout.clone());
|
||||
if !ptr.is_null() {
|
||||
ptr::write_bytes(ptr as *mut u8, 0, layout.size());
|
||||
ptr::write_bytes(ptr, 0, layout.size());
|
||||
}
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) {
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
libc::free(ptr as *mut libc::c_void)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
|
||||
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque
|
||||
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
|
||||
} else {
|
||||
self.realloc_fallback(ptr, layout, new_size)
|
||||
}
|
||||
@ -155,7 +176,7 @@ mod platform {
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))]
|
||||
#[inline]
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque {
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||
// On android we currently target API level 9 which unfortunately
|
||||
// doesn't have the `posix_memalign` API used below. Instead we use
|
||||
// `memalign`, but this unfortunately has the property on some systems
|
||||
@ -173,19 +194,18 @@ mod platform {
|
||||
// [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
|
||||
// [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
|
||||
// /memory/aligned_memory.cc
|
||||
libc::memalign(layout.align(), layout.size()) as *mut Opaque
|
||||
libc::memalign(layout.align(), layout.size()) as *mut u8
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))]
|
||||
#[inline]
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque {
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||
let mut out = ptr::null_mut();
|
||||
let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
|
||||
if ret != 0 {
|
||||
// FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659
|
||||
0 as *mut Opaque
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
out as *mut Opaque
|
||||
out as *mut u8
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -195,7 +215,7 @@ mod platform {
|
||||
mod platform {
|
||||
use MIN_ALIGN;
|
||||
use System;
|
||||
use core::alloc::{GlobalAlloc, Opaque, Layout};
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
type LPVOID = *mut u8;
|
||||
type HANDLE = LPVOID;
|
||||
@ -227,7 +247,7 @@ mod platform {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque {
|
||||
unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
|
||||
let ptr = if layout.align() <= MIN_ALIGN {
|
||||
HeapAlloc(GetProcessHeap(), flags, layout.size())
|
||||
} else {
|
||||
@ -239,29 +259,29 @@ mod platform {
|
||||
align_ptr(ptr, layout.align())
|
||||
}
|
||||
};
|
||||
ptr as *mut Opaque
|
||||
ptr as *mut u8
|
||||
}
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
allocate_with_flags(layout, 0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
allocate_with_flags(layout, HEAP_ZERO_MEMORY)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
if layout.align() <= MIN_ALIGN {
|
||||
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
|
||||
debug_assert!(err != 0, "Failed to free heap memory: {}",
|
||||
GetLastError());
|
||||
} else {
|
||||
let header = get_header(ptr as *mut u8);
|
||||
let header = get_header(ptr);
|
||||
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
|
||||
debug_assert!(err != 0, "Failed to free heap memory: {}",
|
||||
GetLastError());
|
||||
@ -269,9 +289,9 @@ mod platform {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN {
|
||||
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque
|
||||
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
|
||||
} else {
|
||||
self.realloc_fallback(ptr, layout, new_size)
|
||||
}
|
||||
@ -300,32 +320,32 @@ mod platform {
|
||||
mod platform {
|
||||
extern crate dlmalloc;
|
||||
|
||||
use core::alloc::{GlobalAlloc, Layout, Opaque};
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use System;
|
||||
|
||||
// No need for synchronization here as wasm is currently single-threaded
|
||||
static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
|
||||
DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
DLMALLOC.malloc(layout.size(), layout.align())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
|
||||
DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
DLMALLOC.calloc(layout.size(), layout.align())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
|
||||
DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align())
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
DLMALLOC.free(ptr, layout.size(), layout.align())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
|
||||
DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![unstable(feature = "allocator_api",
|
||||
reason = "the precise API and guarantees it provides may be tweaked \
|
||||
slightly, especially to possibly take into account the \
|
||||
types being stored to make room for a future \
|
||||
tracing garbage collector",
|
||||
issue = "32838")]
|
||||
//! Memory allocation APIs
|
||||
|
||||
#![stable(feature = "alloc_module", since = "1.28.0")]
|
||||
|
||||
use cmp;
|
||||
use fmt;
|
||||
@ -22,30 +19,15 @@ use usize;
|
||||
use ptr::{self, NonNull};
|
||||
use num::NonZeroUsize;
|
||||
|
||||
extern {
|
||||
/// An opaque, unsized type. Used for pointers to allocated memory.
|
||||
///
|
||||
/// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull<Opaque>`.
|
||||
/// Such pointers are similar to 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 _
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "alloc_internals", issue = "0")]
|
||||
#[cfg(stage0)]
|
||||
pub type Opaque = u8;
|
||||
|
||||
/// Represents the combination of a starting address and
|
||||
/// a total capacity of the returned block.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[derive(Debug)]
|
||||
pub struct Excess(pub NonNull<Opaque>, pub usize);
|
||||
pub struct Excess(pub NonNull<u8>, pub usize);
|
||||
|
||||
fn size_align<T>() -> (usize, usize) {
|
||||
(mem::size_of::<T>(), mem::align_of::<T>())
|
||||
@ -64,6 +46,7 @@ fn size_align<T>() -> (usize, usize) {
|
||||
/// requests have positive size. A caller to the `Alloc::alloc`
|
||||
/// method must either ensure that conditions like this are met, or
|
||||
/// use specific allocators with looser requirements.)
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Layout {
|
||||
// size of the requested block of memory, measured in bytes.
|
||||
@ -89,6 +72,7 @@ impl Layout {
|
||||
/// * `size`, when rounded up to the nearest multiple of `align`,
|
||||
/// must not overflow (i.e. the rounded value must be less than
|
||||
/// `usize::MAX`).
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
|
||||
if !align.is_power_of_two() {
|
||||
@ -124,20 +108,24 @@ impl Layout {
|
||||
///
|
||||
/// This function is unsafe as it does not verify the preconditions from
|
||||
/// [`Layout::from_size_align`](#method.from_size_align).
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
|
||||
Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
|
||||
}
|
||||
|
||||
/// The minimum size in bytes for a memory block of this layout.
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize { self.size_ }
|
||||
|
||||
/// The minimum byte alignment for a memory block of this layout.
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub fn align(&self) -> usize { self.align_.get() }
|
||||
|
||||
/// Constructs a `Layout` suitable for holding a value of type `T`.
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub fn new<T>() -> Self {
|
||||
let (size, align) = size_align::<T>();
|
||||
@ -154,6 +142,7 @@ impl Layout {
|
||||
/// Produces layout describing a record that could be used to
|
||||
/// allocate backing structure for `T` (which could be a trait
|
||||
/// or other unsized type like a slice).
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub fn for_value<T: ?Sized>(t: &T) -> Self {
|
||||
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
|
||||
@ -181,6 +170,7 @@ impl Layout {
|
||||
/// Panics if the combination of `self.size()` and the given `align`
|
||||
/// violates the conditions listed in
|
||||
/// [`Layout::from_size_align`](#method.from_size_align).
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn align_to(&self, align: usize) -> Self {
|
||||
Layout::from_size_align(self.size(), cmp::max(self.align(), align)).unwrap()
|
||||
@ -202,6 +192,7 @@ impl Layout {
|
||||
/// to be less than or equal to the alignment of the starting
|
||||
/// address for the whole allocated block of memory. One way to
|
||||
/// satisfy this constraint is to ensure `align <= self.align()`.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn padding_needed_for(&self, align: usize) -> usize {
|
||||
let len = self.size();
|
||||
@ -238,6 +229,7 @@ impl Layout {
|
||||
/// of each element in the array.
|
||||
///
|
||||
/// On arithmetic overflow, returns `LayoutErr`.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
|
||||
let padded_size = self.size().checked_add(self.padding_needed_for(self.align()))
|
||||
@ -263,6 +255,7 @@ impl Layout {
|
||||
/// (assuming that the record itself starts at offset 0).
|
||||
///
|
||||
/// On arithmetic overflow, returns `LayoutErr`.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
|
||||
let new_align = cmp::max(self.align(), next.align());
|
||||
@ -289,6 +282,7 @@ impl Layout {
|
||||
/// aligned.
|
||||
///
|
||||
/// On arithmetic overflow, returns `LayoutErr`.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
|
||||
let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
|
||||
@ -310,6 +304,7 @@ impl Layout {
|
||||
/// `extend`.)
|
||||
///
|
||||
/// On arithmetic overflow, returns `LayoutErr`.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
|
||||
let new_size = self.size().checked_add(next.size())
|
||||
@ -321,6 +316,7 @@ impl Layout {
|
||||
/// Creates a layout describing the record for a `[T; n]`.
|
||||
///
|
||||
/// On arithmetic overflow, returns `LayoutErr`.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
|
||||
Layout::new::<T>()
|
||||
@ -332,28 +328,33 @@ impl Layout {
|
||||
}
|
||||
}
|
||||
|
||||
/// The parameters given to `Layout::from_size_align` do not satisfy
|
||||
/// its documented constraints.
|
||||
/// The parameters given to `Layout::from_size_align`
|
||||
/// or some other `Layout` constructor
|
||||
/// do not satisfy its documented constraints.
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct LayoutErr {
|
||||
private: ()
|
||||
}
|
||||
|
||||
// (we need this for downstream impl of trait Error)
|
||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||
impl fmt::Display for LayoutErr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("invalid parameters to Layout::from_size_align")
|
||||
}
|
||||
}
|
||||
|
||||
/// The `AllocErr` error specifies whether an allocation failure is
|
||||
/// specifically due to resource exhaustion or if it is due to
|
||||
/// The `AllocErr` error indicates an allocation failure
|
||||
/// that may be due to resource exhaustion or to
|
||||
/// something wrong when combining the given input arguments with this
|
||||
/// allocator.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct AllocErr;
|
||||
|
||||
// (we need this for downstream impl of trait Error)
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
impl fmt::Display for AllocErr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("memory allocation failed")
|
||||
@ -363,9 +364,11 @@ impl fmt::Display for AllocErr {
|
||||
/// The `CannotReallocInPlace` error is used when `grow_in_place` or
|
||||
/// `shrink_in_place` were unable to reuse the given memory block for
|
||||
/// a requested layout.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct CannotReallocInPlace;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
impl CannotReallocInPlace {
|
||||
pub fn description(&self) -> &str {
|
||||
"cannot reallocate allocator's memory in place"
|
||||
@ -373,6 +376,7 @@ impl CannotReallocInPlace {
|
||||
}
|
||||
|
||||
// (we need this for downstream impl of trait Error)
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
impl fmt::Display for CannotReallocInPlace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.description())
|
||||
@ -380,6 +384,7 @@ impl fmt::Display for CannotReallocInPlace {
|
||||
}
|
||||
|
||||
/// Augments `AllocErr` with a CapacityOverflow variant.
|
||||
// FIXME: should this be in libcore or liballoc?
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub enum CollectionAllocErr {
|
||||
@ -406,32 +411,134 @@ impl From<LayoutErr> for CollectionAllocErr {
|
||||
}
|
||||
}
|
||||
|
||||
/// A memory allocator that can be registered to be the one backing `std::alloc::Global`
|
||||
/// A memory allocator that can be registered as the standard library’s default
|
||||
/// though the `#[global_allocator]` attributes.
|
||||
///
|
||||
/// Some of the methods require that a memory block be *currently
|
||||
/// allocated* via an allocator. This means that:
|
||||
///
|
||||
/// * the starting address for that memory block was previously
|
||||
/// returned by a previous call to an allocation method
|
||||
/// such as `alloc`, and
|
||||
///
|
||||
/// * the memory block has not been subsequently deallocated, where
|
||||
/// blocks are deallocated either by being passed to a deallocation
|
||||
/// method such as `dealloc` or by being
|
||||
/// passed to a reallocation method that returns a non-null pointer.
|
||||
///
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::alloc::{GlobalAlloc, Layout, alloc};
|
||||
/// use std::ptr::null_mut;
|
||||
///
|
||||
/// struct MyAllocator;
|
||||
///
|
||||
/// unsafe impl GlobalAlloc for MyAllocator {
|
||||
/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
|
||||
/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
|
||||
/// }
|
||||
///
|
||||
/// #[global_allocator]
|
||||
/// static A: MyAllocator = MyAllocator;
|
||||
///
|
||||
/// fn main() {
|
||||
/// unsafe {
|
||||
/// assert!(alloc(Layout::new::<u32>()).is_null())
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
|
||||
/// implementors must ensure that they adhere to these contracts:
|
||||
///
|
||||
/// * It's undefined behavior if global allocators unwind. This restriction may
|
||||
/// be lifted in the future, but currently a panic from any of these
|
||||
/// functions may lead to memory unsafety.
|
||||
///
|
||||
/// * `Layout` queries and calculations in general must be correct. Callers of
|
||||
/// this trait are allowed to rely on the contracts defined on each method,
|
||||
/// and implementors must ensure such contracts remain true.
|
||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||
pub unsafe trait GlobalAlloc {
|
||||
/// Allocate memory as described by the given `layout`.
|
||||
///
|
||||
/// Returns a pointer to newly-allocated memory,
|
||||
/// or NULL to indicate allocation failure.
|
||||
/// or null to indicate allocation failure.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// **FIXME:** what are the exact requirements?
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque;
|
||||
/// This function is unsafe because undefined behavior can result
|
||||
/// if the caller does not ensure that `layout` has non-zero size.
|
||||
///
|
||||
/// (Extension subtraits might provide more specific bounds on
|
||||
/// behavior, e.g. guarantee a sentinel address or a null pointer
|
||||
/// in response to a zero-size allocation request.)
|
||||
///
|
||||
/// The allocated block of memory may or may not be initialized.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returning a null pointer indicates that either memory is exhausted
|
||||
/// or `layout` does not meet allocator's size or alignment constraints.
|
||||
///
|
||||
/// Implementations are encouraged to return null on memory
|
||||
/// exhaustion rather than aborting, but this is not
|
||||
/// a strict requirement. (Specifically: it is *legal* to
|
||||
/// implement this trait atop an underlying native allocation
|
||||
/// library that aborts on memory exhaustion.)
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// allocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8;
|
||||
|
||||
/// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// **FIXME:** what are the exact requirements?
|
||||
/// In particular around layout *fit*. (See docs for the `Alloc` trait.)
|
||||
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout);
|
||||
/// This function is unsafe because undefined behavior can result
|
||||
/// if the caller does not ensure all of the following:
|
||||
///
|
||||
/// * `ptr` must denote a block of memory currently allocated via
|
||||
/// this allocator,
|
||||
///
|
||||
/// * `layout` must be the same layout that was used
|
||||
/// to allocated that block of memory,
|
||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
|
||||
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
|
||||
/// Behaves like `alloc`, but also ensures that the contents
|
||||
/// are set to zero before being returned.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe for the same reasons that `alloc` is.
|
||||
/// However the allocated block of memory is guaranteed to be initialized.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returning a null pointer indicates that either memory is exhausted
|
||||
/// or `layout` does not meet allocator's size or alignment constraints,
|
||||
/// just as in `alloc`.
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// allocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
let size = layout.size();
|
||||
let ptr = self.alloc(layout);
|
||||
if !ptr.is_null() {
|
||||
ptr::write_bytes(ptr as *mut u8, 0, size);
|
||||
ptr::write_bytes(ptr, 0, size);
|
||||
}
|
||||
ptr
|
||||
}
|
||||
@ -439,26 +546,61 @@ pub unsafe trait GlobalAlloc {
|
||||
/// Shink or grow a block of memory to the given `new_size`.
|
||||
/// The block is described by the given `ptr` pointer and `layout`.
|
||||
///
|
||||
/// Return a new pointer (which may or may not be the same as `ptr`),
|
||||
/// or NULL to indicate reallocation failure.
|
||||
/// If this returns a non-null pointer, then ownership of the memory block
|
||||
/// referenced by `ptr` has been transferred to this alloctor.
|
||||
/// The memory may or may not have been deallocated,
|
||||
/// and should be considered unusable (unless of course it was
|
||||
/// transferred back to the caller again via the return value of
|
||||
/// this method).
|
||||
///
|
||||
/// If reallocation is successful, the old `ptr` pointer is considered
|
||||
/// to have been deallocated.
|
||||
/// If this method returns null, then ownership of the memory
|
||||
/// block has not been transferred to this allocator, and the
|
||||
/// contents of the memory block are unaltered.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`,
|
||||
/// must not overflow (i.e. the rounded value must be less than `usize::MAX`).
|
||||
/// This function is unsafe because undefined behavior can result
|
||||
/// if the caller does not ensure all of the following:
|
||||
///
|
||||
/// **FIXME:** what are the exact requirements?
|
||||
/// In particular around layout *fit*. (See docs for the `Alloc` trait.)
|
||||
unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
|
||||
/// * `ptr` must be currently allocated via this allocator,
|
||||
///
|
||||
/// * `layout` must be the same layout that was used
|
||||
/// to allocated that block of memory,
|
||||
///
|
||||
/// * `new_size` must be greater than zero.
|
||||
///
|
||||
/// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
|
||||
/// must not overflow (i.e. the rounded value must be less than `usize::MAX`).
|
||||
///
|
||||
/// (Extension subtraits might provide more specific bounds on
|
||||
/// behavior, e.g. guarantee a sentinel address or a null pointer
|
||||
/// in response to a zero-size allocation request.)
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns null if the new layout does not meet the size
|
||||
/// and alignment constraints of the allocator, or if reallocation
|
||||
/// otherwise fails.
|
||||
///
|
||||
/// Implementations are encouraged to return null on memory
|
||||
/// exhaustion rather than panicking or aborting, but this is not
|
||||
/// a strict requirement. (Specifically: it is *legal* to
|
||||
/// implement this trait atop an underlying native allocation
|
||||
/// library that aborts on memory exhaustion.)
|
||||
///
|
||||
/// Clients wishing to abort computation in response to a
|
||||
/// reallocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
|
||||
let new_ptr = self.alloc(new_layout);
|
||||
if !new_ptr.is_null() {
|
||||
ptr::copy_nonoverlapping(
|
||||
ptr as *const u8,
|
||||
new_ptr as *mut u8,
|
||||
ptr,
|
||||
new_ptr,
|
||||
cmp::min(layout.size(), new_size),
|
||||
);
|
||||
self.dealloc(ptr, layout);
|
||||
@ -540,27 +682,22 @@ pub unsafe trait GlobalAlloc {
|
||||
/// retain their validity until at least the instance of `Alloc` is dropped
|
||||
/// itself.
|
||||
///
|
||||
/// * It's undefined behavior if global allocators unwind. This restriction may
|
||||
/// be lifted in the future, but currently a panic from any of these
|
||||
/// functions may lead to memory unsafety. Note that as of the time of this
|
||||
/// writing allocators *not* intending to be global allocators can still panic
|
||||
/// in their implementation without violating memory safety.
|
||||
///
|
||||
/// * `Layout` queries and calculations in general must be correct. Callers of
|
||||
/// this trait are allowed to rely on the contracts defined on each method,
|
||||
/// and implementors must ensure such contracts remain true.
|
||||
///
|
||||
/// Note that this list may get tweaked over time as clarifications are made in
|
||||
/// the future. Additionally global allocators may gain unique requirements for
|
||||
/// how to safely implement one in the future as well.
|
||||
/// the future.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub unsafe trait Alloc {
|
||||
|
||||
// (Note: existing allocators have unspecified but well-defined
|
||||
// (Note: some existing allocators have unspecified but well-defined
|
||||
// behavior in response to a zero size allocation request ;
|
||||
// e.g. in C, `malloc` of 0 will either return a null pointer or a
|
||||
// unique pointer, but will not have arbitrary undefined
|
||||
// behavior. Rust should consider revising the alloc::heap crate
|
||||
// to reflect this reality.)
|
||||
// behavior.
|
||||
// However in jemalloc for example,
|
||||
// `mallocx(0)` is documented as undefined behavior.)
|
||||
|
||||
/// Returns a pointer meeting the size and alignment guarantees of
|
||||
/// `layout`.
|
||||
@ -596,9 +733,11 @@ pub unsafe trait Alloc {
|
||||
/// library that aborts on memory exhaustion.)
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// allocation error are encouraged to call the allocator's `oom`
|
||||
/// method, rather than directly invoking `panic!` or similar.
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr>;
|
||||
/// allocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr>;
|
||||
|
||||
/// Deallocate the memory referenced by `ptr`.
|
||||
///
|
||||
@ -615,7 +754,7 @@ pub unsafe trait Alloc {
|
||||
/// * In addition to fitting the block of memory `layout`, the
|
||||
/// alignment of the `layout` must match the alignment used
|
||||
/// to allocate that block of memory.
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout);
|
||||
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);
|
||||
|
||||
// == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS ==
|
||||
// usable_size
|
||||
@ -703,13 +842,15 @@ pub unsafe trait Alloc {
|
||||
/// implement this trait atop an underlying native allocation
|
||||
/// library that aborts on memory exhaustion.)
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// reallocation error are encouraged to call the allocator's `oom`
|
||||
/// method, rather than directly invoking `panic!` or similar.
|
||||
/// Clients wishing to abort computation in response to a
|
||||
/// reallocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
unsafe fn realloc(&mut self,
|
||||
ptr: NonNull<Opaque>,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
|
||||
new_size: usize) -> Result<NonNull<u8>, AllocErr> {
|
||||
let old_size = layout.size();
|
||||
|
||||
if new_size >= old_size {
|
||||
@ -726,8 +867,8 @@ pub unsafe trait Alloc {
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
|
||||
let result = self.alloc(new_layout);
|
||||
if let Ok(new_ptr) = result {
|
||||
ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8,
|
||||
new_ptr.as_ptr() as *mut u8,
|
||||
ptr::copy_nonoverlapping(ptr.as_ptr(),
|
||||
new_ptr.as_ptr(),
|
||||
cmp::min(old_size, new_size));
|
||||
self.dealloc(ptr, layout);
|
||||
}
|
||||
@ -748,13 +889,15 @@ pub unsafe trait Alloc {
|
||||
/// constraints, just as in `alloc`.
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// allocation error are encouraged to call the allocator's `oom`
|
||||
/// method, rather than directly invoking `panic!` or similar.
|
||||
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
|
||||
/// allocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
|
||||
let size = layout.size();
|
||||
let p = self.alloc(layout);
|
||||
if let Ok(p) = p {
|
||||
ptr::write_bytes(p.as_ptr() as *mut u8, 0, size);
|
||||
ptr::write_bytes(p.as_ptr(), 0, size);
|
||||
}
|
||||
p
|
||||
}
|
||||
@ -774,8 +917,10 @@ pub unsafe trait Alloc {
|
||||
/// constraints, just as in `alloc`.
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// allocation error are encouraged to call the allocator's `oom`
|
||||
/// method, rather than directly invoking `panic!` or similar.
|
||||
/// allocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
|
||||
let usable_size = self.usable_size(&layout);
|
||||
self.alloc(layout).map(|p| Excess(p, usable_size.1))
|
||||
@ -795,11 +940,13 @@ pub unsafe trait Alloc {
|
||||
/// `layout` does not meet allocator's size or alignment
|
||||
/// constraints, just as in `realloc`.
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// reallocation error are encouraged to call the allocator's `oom`
|
||||
/// method, rather than directly invoking `panic!` or similar.
|
||||
/// Clients wishing to abort computation in response to a
|
||||
/// reallocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
unsafe fn realloc_excess(&mut self,
|
||||
ptr: NonNull<Opaque>,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
new_size: usize) -> Result<Excess, AllocErr> {
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
|
||||
@ -840,11 +987,11 @@ pub unsafe trait Alloc {
|
||||
/// could fit `layout`.
|
||||
///
|
||||
/// Note that one cannot pass `CannotReallocInPlace` to the `oom`
|
||||
/// method; clients are expected either to be able to recover from
|
||||
/// function; clients are expected either to be able to recover from
|
||||
/// `grow_in_place` failures without aborting, or to fall back on
|
||||
/// another reallocation method before resorting to an abort.
|
||||
unsafe fn grow_in_place(&mut self,
|
||||
ptr: NonNull<Opaque>,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
new_size: usize) -> Result<(), CannotReallocInPlace> {
|
||||
let _ = ptr; // this default implementation doesn't care about the actual address.
|
||||
@ -895,11 +1042,11 @@ pub unsafe trait Alloc {
|
||||
/// could fit `layout`.
|
||||
///
|
||||
/// Note that one cannot pass `CannotReallocInPlace` to the `oom`
|
||||
/// method; clients are expected either to be able to recover from
|
||||
/// function; clients are expected either to be able to recover from
|
||||
/// `shrink_in_place` failures without aborting, or to fall back
|
||||
/// on another reallocation method before resorting to an abort.
|
||||
unsafe fn shrink_in_place(&mut self,
|
||||
ptr: NonNull<Opaque>,
|
||||
ptr: NonNull<u8>,
|
||||
layout: Layout,
|
||||
new_size: usize) -> Result<(), CannotReallocInPlace> {
|
||||
let _ = ptr; // this default implementation doesn't care about the actual address.
|
||||
@ -943,8 +1090,10 @@ pub unsafe trait Alloc {
|
||||
/// will *not* yield undefined behavior.
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// allocation error are encouraged to call the allocator's `oom`
|
||||
/// method, rather than directly invoking `panic!` or similar.
|
||||
/// allocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr>
|
||||
where Self: Sized
|
||||
{
|
||||
@ -978,7 +1127,7 @@ pub unsafe trait Alloc {
|
||||
{
|
||||
let k = Layout::new::<T>();
|
||||
if k.size() > 0 {
|
||||
self.dealloc(ptr.as_opaque(), k);
|
||||
self.dealloc(ptr.cast(), k);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1010,8 +1159,10 @@ pub unsafe trait Alloc {
|
||||
/// Always returns `Err` on arithmetic overflow.
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// allocation error are encouraged to call the allocator's `oom`
|
||||
/// method, rather than directly invoking `panic!` or similar.
|
||||
/// allocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr>
|
||||
where Self: Sized
|
||||
{
|
||||
@ -1054,9 +1205,11 @@ pub unsafe trait Alloc {
|
||||
///
|
||||
/// Always returns `Err` on arithmetic overflow.
|
||||
///
|
||||
/// Clients wishing to abort computation in response to an
|
||||
/// reallocation error are encouraged to call the allocator's `oom`
|
||||
/// method, rather than directly invoking `panic!` or similar.
|
||||
/// Clients wishing to abort computation in response to a
|
||||
/// reallocation error are encouraged to call the [`oom`] function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// [`oom`]: ../../alloc/alloc/fn.oom.html
|
||||
unsafe fn realloc_array<T>(&mut self,
|
||||
ptr: NonNull<T>,
|
||||
n_old: usize,
|
||||
@ -1066,7 +1219,7 @@ pub unsafe trait Alloc {
|
||||
match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) {
|
||||
(Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => {
|
||||
debug_assert!(k_old.align() == k_new.align());
|
||||
self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast)
|
||||
self.realloc(ptr.cast(), k_old.clone(), k_new.size()).map(NonNull::cast)
|
||||
}
|
||||
_ => {
|
||||
Err(AllocErr)
|
||||
@ -1099,7 +1252,7 @@ pub unsafe trait Alloc {
|
||||
{
|
||||
match Layout::array::<T>(n) {
|
||||
Ok(ref k) if k.size() > 0 => {
|
||||
Ok(self.dealloc(ptr.as_opaque(), k.clone()))
|
||||
Ok(self.dealloc(ptr.cast(), k.clone()))
|
||||
}
|
||||
_ => {
|
||||
Err(AllocErr)
|
||||
|
@ -215,13 +215,6 @@ pub mod task;
|
||||
#[allow(missing_docs)]
|
||||
pub mod alloc;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
|
||||
/// Use the `alloc` module instead.
|
||||
pub mod heap {
|
||||
pub use alloc::*;
|
||||
}
|
||||
|
||||
// note: does not need to be public
|
||||
mod iter_private;
|
||||
mod nonzero;
|
||||
|
@ -2922,14 +2922,6 @@ impl<T: ?Sized> NonNull<T> {
|
||||
NonNull::new_unchecked(self.as_ptr() as *mut U)
|
||||
}
|
||||
}
|
||||
|
||||
/// Cast to an `Opaque` pointer
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub fn as_opaque(self) -> NonNull<::alloc::Opaque> {
|
||||
unsafe {
|
||||
NonNull::new_unchecked(self.as_ptr() as _)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "nonnull", since = "1.25.0")]
|
||||
|
@ -237,7 +237,7 @@ impl<'a> AllocFnFactory<'a> {
|
||||
let ident = ident();
|
||||
args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
|
||||
let arg = self.cx.expr_ident(self.span, ident);
|
||||
self.cx.expr_cast(self.span, arg, self.ptr_opaque())
|
||||
self.cx.expr_cast(self.span, arg, self.ptr_u8())
|
||||
}
|
||||
|
||||
AllocatorTy::Usize => {
|
||||
@ -281,17 +281,4 @@ impl<'a> AllocFnFactory<'a> {
|
||||
let ty_u8 = self.cx.ty_path(u8);
|
||||
self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
|
||||
}
|
||||
|
||||
fn ptr_opaque(&self) -> P<Ty> {
|
||||
let opaque = self.cx.path(
|
||||
self.span,
|
||||
vec![
|
||||
self.core,
|
||||
Ident::from_str("alloc"),
|
||||
Ident::from_str("Opaque"),
|
||||
],
|
||||
);
|
||||
let ty_opaque = self.cx.ty_path(opaque);
|
||||
self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable)
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,7 @@
|
||||
|
||||
#![sanitizer_runtime]
|
||||
#![feature(alloc_system)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(global_allocator)]
|
||||
#![cfg_attr(stage0, feature(global_allocator))]
|
||||
#![feature(sanitizer_runtime)]
|
||||
#![feature(staged_api)]
|
||||
#![no_std]
|
||||
|
@ -9,10 +9,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![sanitizer_runtime]
|
||||
#![feature(sanitizer_runtime)]
|
||||
#![feature(alloc_system)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(global_allocator)]
|
||||
#![cfg_attr(stage0, feature(global_allocator))]
|
||||
#![feature(sanitizer_runtime)]
|
||||
#![feature(staged_api)]
|
||||
#![no_std]
|
||||
#![unstable(feature = "sanitizer_runtime_lib",
|
||||
|
@ -9,10 +9,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![sanitizer_runtime]
|
||||
#![feature(sanitizer_runtime)]
|
||||
#![feature(alloc_system)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(global_allocator)]
|
||||
#![cfg_attr(stage0, feature(global_allocator))]
|
||||
#![feature(sanitizer_runtime)]
|
||||
#![feature(staged_api)]
|
||||
#![no_std]
|
||||
#![unstable(feature = "sanitizer_runtime_lib",
|
||||
|
@ -10,8 +10,7 @@
|
||||
|
||||
#![sanitizer_runtime]
|
||||
#![feature(alloc_system)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(global_allocator)]
|
||||
#![cfg_attr(stage0, feature(global_allocator))]
|
||||
#![feature(sanitizer_runtime)]
|
||||
#![feature(staged_api)]
|
||||
#![no_std]
|
||||
|
@ -8,19 +8,84 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! dox
|
||||
//! Memory allocation APIs
|
||||
//!
|
||||
//! In a given program, the standard library has one “global” memory allocator
|
||||
//! that is used for example by `Box<T>` and `Vec<T>`.
|
||||
//!
|
||||
//! Currently the default global allocator is unspecified.
|
||||
//! The compiler may link to a version of [jemalloc] on some platforms,
|
||||
//! but this is not guaranteed.
|
||||
//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed
|
||||
//! to use the [`System`] by default.
|
||||
//!
|
||||
//! [jemalloc]: https://github.com/jemalloc/jemalloc
|
||||
//! [`System`]: struct.System.html
|
||||
//!
|
||||
//! # The `#[global_allocator]` attribute
|
||||
//!
|
||||
//! This attribute allows configuring the choice of global allocator.
|
||||
//! You can use this to implement a completely custom global allocator
|
||||
//! to route all default allocation requests to a custom object.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::alloc::{GlobalAlloc, System, Layout};
|
||||
//!
|
||||
//! struct MyAllocator;
|
||||
//!
|
||||
//! unsafe impl GlobalAlloc for MyAllocator {
|
||||
//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
//! System.alloc(layout)
|
||||
//! }
|
||||
//!
|
||||
//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
//! System.dealloc(ptr, layout)
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[global_allocator]
|
||||
//! static GLOBAL: MyAllocator = MyAllocator;
|
||||
//!
|
||||
//! fn main() {
|
||||
//! // This `Vec` will allocate memory through `GLOBAL` above
|
||||
//! let mut v = Vec::new();
|
||||
//! v.push(1);
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The attribute is used on a `static` item whose type implements the
|
||||
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
|
||||
//!
|
||||
//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
|
||||
//!
|
||||
//! ```rust,ignore (demonstrates crates.io usage)
|
||||
//! extern crate jemallocator;
|
||||
//!
|
||||
//! use jemallacator::Jemalloc;
|
||||
//!
|
||||
//! #[global_allocator]
|
||||
//! static GLOBAL: Jemalloc = Jemalloc;
|
||||
//!
|
||||
//! fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! The `#[global_allocator]` can only be used once in a crate
|
||||
//! or its recursive dependencies.
|
||||
|
||||
#![unstable(issue = "32838", feature = "allocator_api")]
|
||||
|
||||
#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
|
||||
#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom};
|
||||
#[doc(inline)] pub use alloc_system::System;
|
||||
#[doc(inline)] pub use core::alloc::*;
|
||||
#![stable(feature = "alloc_module", since = "1.28.0")]
|
||||
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
use core::{mem, ptr};
|
||||
use sys_common::util::dumb_print;
|
||||
|
||||
#[stable(feature = "alloc_module", since = "1.28.0")]
|
||||
#[doc(inline)]
|
||||
pub use alloc_crate::alloc::*;
|
||||
|
||||
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
||||
#[doc(inline)]
|
||||
pub use alloc_system::System;
|
||||
|
||||
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
/// Registers a custom OOM hook, replacing any that was previously registered.
|
||||
@ -34,6 +99,7 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
|
||||
/// about the allocation that failed.
|
||||
///
|
||||
/// The OOM hook is a global resource.
|
||||
#[unstable(feature = "oom_hook", issue = "51245")]
|
||||
pub fn set_oom_hook(hook: fn(Layout)) {
|
||||
HOOK.store(hook as *mut (), Ordering::SeqCst);
|
||||
}
|
||||
@ -43,6 +109,7 @@ pub fn set_oom_hook(hook: fn(Layout)) {
|
||||
/// *See also the function [`set_oom_hook`].*
|
||||
///
|
||||
/// If no custom hook is registered, the default hook will be returned.
|
||||
#[unstable(feature = "oom_hook", issue = "51245")]
|
||||
pub fn take_oom_hook() -> fn(Layout) {
|
||||
let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
|
||||
if hook.is_null() {
|
||||
@ -59,6 +126,7 @@ fn default_oom_hook(layout: Layout) {
|
||||
#[cfg(not(test))]
|
||||
#[doc(hidden)]
|
||||
#[lang = "oom"]
|
||||
#[unstable(feature = "alloc_internals", issue = "0")]
|
||||
pub extern fn rust_oom(layout: Layout) -> ! {
|
||||
let hook = HOOK.load(Ordering::SeqCst);
|
||||
let hook: fn(Layout) = if hook.is_null() {
|
||||
@ -73,8 +141,9 @@ pub extern fn rust_oom(layout: Layout) -> ! {
|
||||
#[cfg(not(test))]
|
||||
#[doc(hidden)]
|
||||
#[allow(unused_attributes)]
|
||||
#[unstable(feature = "alloc_internals", issue = "0")]
|
||||
pub mod __default_lib_allocator {
|
||||
use super::{System, Layout, GlobalAlloc, Opaque};
|
||||
use super::{System, Layout, GlobalAlloc};
|
||||
// for symbol names src/librustc/middle/allocator.rs
|
||||
// for signatures src/librustc_allocator/lib.rs
|
||||
|
||||
@ -85,7 +154,7 @@ pub mod __default_lib_allocator {
|
||||
#[rustc_std_internal_symbol]
|
||||
pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
|
||||
let layout = Layout::from_size_align_unchecked(size, align);
|
||||
System.alloc(layout) as *mut u8
|
||||
System.alloc(layout)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -93,7 +162,7 @@ pub mod __default_lib_allocator {
|
||||
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
|
||||
size: usize,
|
||||
align: usize) {
|
||||
System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align))
|
||||
System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -103,13 +172,13 @@ pub mod __default_lib_allocator {
|
||||
align: usize,
|
||||
new_size: usize) -> *mut u8 {
|
||||
let old_layout = Layout::from_size_align_unchecked(old_size, align);
|
||||
System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8
|
||||
System.realloc(ptr, old_layout, new_size)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[rustc_std_internal_symbol]
|
||||
pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
|
||||
let layout = Layout::from_size_align_unchecked(size, align);
|
||||
System.alloc_zeroed(layout) as *mut u8
|
||||
System.alloc_zeroed(layout)
|
||||
}
|
||||
}
|
||||
|
@ -1124,7 +1124,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
|
||||
let (layout, _) = calculate_layout::<K, V>(self.capacity())
|
||||
.unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
|
||||
unsafe {
|
||||
Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout);
|
||||
Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout);
|
||||
// Remember how everything was allocated out of one buffer
|
||||
// during initialization? We only need one call to free here.
|
||||
}
|
||||
|
@ -438,7 +438,7 @@ pub use self::hash_map::HashMap;
|
||||
pub use self::hash_set::HashSet;
|
||||
|
||||
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
|
||||
pub use heap::CollectionAllocErr;
|
||||
pub use alloc::CollectionAllocErr;
|
||||
|
||||
mod hash;
|
||||
|
||||
|
@ -23,13 +23,13 @@
|
||||
// coherence challenge (e.g., specialization, neg impls, etc) we can
|
||||
// reconsider what crate these items belong in.
|
||||
|
||||
use alloc::{AllocErr, LayoutErr, CannotReallocInPlace};
|
||||
use any::TypeId;
|
||||
use borrow::Cow;
|
||||
use cell;
|
||||
use char;
|
||||
use core::array;
|
||||
use fmt::{self, Debug, Display};
|
||||
use heap::{AllocErr, LayoutErr, CannotReallocInPlace};
|
||||
use mem::transmute;
|
||||
use num;
|
||||
use str;
|
||||
|
@ -264,7 +264,6 @@
|
||||
#![feature(fnbox)]
|
||||
#![feature(futures_api)]
|
||||
#![feature(hashmap_internals)]
|
||||
#![feature(heap_api)]
|
||||
#![feature(int_error_internals)]
|
||||
#![feature(integer_atomics)]
|
||||
#![feature(into_cow)]
|
||||
@ -500,13 +499,6 @@ pub mod process;
|
||||
pub mod sync;
|
||||
pub mod time;
|
||||
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
|
||||
/// Use the `alloc` module instead.
|
||||
pub mod heap {
|
||||
pub use alloc::*;
|
||||
}
|
||||
|
||||
// Platform-abstraction modules
|
||||
#[macro_use]
|
||||
mod sys_common;
|
||||
|
@ -357,8 +357,6 @@ declare_features! (
|
||||
// Trait aliases
|
||||
(active, trait_alias, "1.24.0", Some(41517), None),
|
||||
|
||||
// global allocators and their internals
|
||||
(active, global_allocator, "1.20.0", Some(27389), None),
|
||||
// rustc internal
|
||||
(active, allocator_internals, "1.20.0", None, None),
|
||||
|
||||
@ -615,6 +613,8 @@ declare_features! (
|
||||
(accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
|
||||
// Termination trait in tests (RFC 1937)
|
||||
(accepted, termination_trait_test, "1.27.0", Some(48854), None),
|
||||
// The #[global_allocator] attribute
|
||||
(accepted, global_allocator, "1.28.0", Some(27389), None),
|
||||
);
|
||||
|
||||
// If you change this, please modify src/doc/unstable-book as well. You must
|
||||
@ -776,11 +776,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
|
||||
"the `#[rustc_const_unstable]` attribute \
|
||||
is an internal feature",
|
||||
cfg_fn!(rustc_const_unstable))),
|
||||
("global_allocator", Normal, Gated(Stability::Unstable,
|
||||
"global_allocator",
|
||||
"the `#[global_allocator]` attribute is \
|
||||
an experimental feature",
|
||||
cfg_fn!(global_allocator))),
|
||||
("global_allocator", Normal, Ungated),
|
||||
("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
|
||||
"allocator_internals",
|
||||
"the `#[default_lib_allocator]` \
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(global_allocator, allocator_api)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
use std::alloc::System;
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(global_allocator, allocator_api)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
use std::alloc::System;
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(global_allocator)]
|
||||
|
||||
#[global_allocator]
|
||||
fn foo() {} //~ ERROR: allocators must be statics
|
||||
|
@ -8,8 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(global_allocator, heap_api)]
|
||||
|
||||
#[global_allocator]
|
||||
static A: usize = 0;
|
||||
//~^ the trait bound `usize:
|
||||
|
@ -8,8 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(global_allocator, allocator_api)]
|
||||
|
||||
use std::alloc::System;
|
||||
|
||||
#[global_allocator]
|
||||
|
@ -12,8 +12,6 @@
|
||||
// no-prefer-dynamic
|
||||
// error-pattern: the #[global_allocator] in
|
||||
|
||||
#![feature(global_allocator, allocator_api)]
|
||||
|
||||
extern crate system_allocator;
|
||||
|
||||
use std::alloc::System;
|
||||
|
@ -13,7 +13,6 @@
|
||||
// no-prefer-dynamic
|
||||
// error-pattern: the #[global_allocator] in
|
||||
|
||||
#![feature(global_allocator)]
|
||||
|
||||
extern crate system_allocator;
|
||||
extern crate system_allocator2;
|
||||
|
@ -18,6 +18,11 @@
|
||||
mod cross_crate {
|
||||
extern crate lint_stability_fields;
|
||||
|
||||
mod reexport {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::lint_stability_fields::*;
|
||||
}
|
||||
|
||||
use self::lint_stability_fields::*;
|
||||
|
||||
pub fn foo() {
|
||||
@ -73,6 +78,8 @@ mod cross_crate {
|
||||
// the patterns are all fine:
|
||||
{ .. } = x;
|
||||
|
||||
// Unstable items are still unstable even when used through a stable "pub use".
|
||||
let x = reexport::Unstable2(1, 2, 3); //~ ERROR use of unstable
|
||||
|
||||
let x = Unstable2(1, 2, 3); //~ ERROR use of unstable
|
||||
|
||||
|
@ -16,11 +16,11 @@ use std::alloc::*;
|
||||
pub struct A;
|
||||
|
||||
unsafe impl GlobalAlloc for A {
|
||||
unsafe fn alloc(&self, _: Layout) -> *mut Opaque {
|
||||
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
|
||||
loop {}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, _ptr: *mut Opaque, _: Layout) {
|
||||
unsafe fn dealloc(&self, _ptr: *mut u8, _: Layout) {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(global_allocator)]
|
||||
#![crate_type = "cdylib"]
|
||||
|
||||
extern crate bar;
|
||||
|
@ -8,11 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(global_allocator, alloc_system, allocator_api)]
|
||||
extern crate alloc_system;
|
||||
|
||||
use std::alloc::System;
|
||||
use std::collections::VecDeque;
|
||||
use alloc_system::System;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: System = System;
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(global_allocator)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
extern crate custom;
|
||||
|
@ -13,18 +13,18 @@
|
||||
#![feature(heap_api, allocator_api)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
use std::alloc::{GlobalAlloc, System, Layout, Opaque};
|
||||
use std::alloc::{GlobalAlloc, System, Layout};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
pub struct A(pub AtomicUsize);
|
||||
|
||||
unsafe impl GlobalAlloc for A {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
self.0.fetch_add(1, Ordering::SeqCst);
|
||||
System.alloc(layout)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
self.0.fetch_add(1, Ordering::SeqCst);
|
||||
System.dealloc(ptr, layout)
|
||||
}
|
||||
|
@ -11,11 +11,11 @@
|
||||
// aux-build:helper.rs
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(global_allocator, heap_api, allocator_api)]
|
||||
#![feature(allocator_api)]
|
||||
|
||||
extern crate helper;
|
||||
|
||||
use std::alloc::{self, Global, Alloc, System, Layout, Opaque};
|
||||
use std::alloc::{self, Global, Alloc, System, Layout};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
||||
|
||||
static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
@ -23,12 +23,12 @@ static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
struct A;
|
||||
|
||||
unsafe impl alloc::GlobalAlloc for A {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
HITS.fetch_add(1, Ordering::SeqCst);
|
||||
System.alloc(layout)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
HITS.fetch_add(1, Ordering::SeqCst);
|
||||
System.dealloc(ptr, layout)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
// aux-build:helper.rs
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(global_allocator, heap_api, allocator_api)]
|
||||
#![feature(allocator_api)]
|
||||
|
||||
extern crate custom;
|
||||
extern crate helper;
|
||||
|
@ -19,7 +19,7 @@ extern crate custom;
|
||||
extern crate custom_as_global;
|
||||
extern crate helper;
|
||||
|
||||
use std::alloc::{Global, Alloc, GlobalAlloc, System, Layout};
|
||||
use std::alloc::{alloc, dealloc, GlobalAlloc, System, Layout};
|
||||
use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
|
||||
|
||||
static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
|
||||
@ -30,10 +30,10 @@ fn main() {
|
||||
let layout = Layout::from_size_align(4, 2).unwrap();
|
||||
|
||||
// Global allocator routes to the `custom_as_global` global
|
||||
let ptr = Global.alloc(layout.clone());
|
||||
let ptr = alloc(layout.clone());
|
||||
helper::work_with(&ptr);
|
||||
assert_eq!(custom_as_global::get(), n + 1);
|
||||
Global.dealloc(ptr, layout.clone());
|
||||
dealloc(ptr, layout.clone());
|
||||
assert_eq!(custom_as_global::get(), n + 2);
|
||||
|
||||
// Usage of the system allocator avoids all globals
|
||||
|
@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool {
|
||||
println!("deallocate({:?}, {:?}", ptr, layout);
|
||||
}
|
||||
|
||||
Global.dealloc(NonNull::new_unchecked(ptr).as_opaque(), layout);
|
||||
Global.dealloc(NonNull::new_unchecked(ptr), layout);
|
||||
}
|
||||
|
||||
unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 {
|
||||
@ -72,7 +72,7 @@ unsafe fn test_triangle() -> bool {
|
||||
println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new);
|
||||
}
|
||||
|
||||
let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old, new.size())
|
||||
let ret = Global.realloc(NonNull::new_unchecked(ptr), old, new.size())
|
||||
.unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align())));
|
||||
|
||||
if PRINT {
|
||||
|
@ -11,8 +11,6 @@
|
||||
// compile-flags: -Z thinlto -C codegen-units=2
|
||||
// min-llvm-version 4.0
|
||||
|
||||
#![feature(allocator_api, global_allocator)]
|
||||
|
||||
#[global_allocator]
|
||||
static A: std::alloc::System = std::alloc::System;
|
||||
|
||||
|
@ -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…
x
Reference in New Issue
Block a user