Skip to content

Commit 4e69e86

Browse files
committed
Associate an allocator to boxes
This turns `Box<T>` into `Box<T, A = Global>`, with a `A: Alloc` bound for impls. Ideally, inherent methods like `Box::new` would be applied to `Box<T, A: Alloc + Default>`, but as of now, that would be backwards incompatible because it would require type annotations in places where they currently aren't required. `impl FromIterator` is not covered because it relies on `Vec`, which would need allocator awareness. `DispatchFromDyn` is left out or being generic over `A` because there is no bound that would make it work currently. `FnBox` is left out because it's related to `DispatchFromDyn`.
1 parent 07a364e commit 4e69e86

11 files changed

+252
-122
lines changed

src/liballoc/alloc.rs

+40-11
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,35 @@
33
#![stable(feature = "alloc_module", since = "1.28.0")]
44

55
use core::intrinsics::{min_align_of_val, size_of_val};
6+
#[cfg(stage0)]
7+
use core::marker::PhantomData;
68
use core::ptr::{NonNull, Unique};
79
use core::usize;
810

911
#[stable(feature = "alloc_module", since = "1.28.0")]
1012
#[doc(inline)]
1113
pub use core::alloc::*;
1214

15+
#[cfg(stage0)]
16+
#[unstable(feature = "allocator_api", issue = "32838")]
17+
// pub to make the compiler happy wrt the trait being made public by the impls in e.g. boxed.rs.
18+
pub trait Stage0Alloc = Alloc + Default;
19+
20+
#[cfg(not(stage0))]
21+
pub(crate) use Alloc as Stage0Alloc;
22+
23+
#[cfg(stage0)]
24+
pub(crate) fn stage0_phantom<A>(_a: A) -> PhantomData<A> { PhantomData }
25+
26+
#[cfg(not(stage0))]
27+
pub(crate) fn stage0_phantom<A>(a: A) -> A { a }
28+
29+
#[cfg(stage0)]
30+
pub(crate) fn stage0_unphantom<A: Default>(_a: PhantomData<A>) -> A { A::default() }
31+
32+
#[cfg(not(stage0))]
33+
pub(crate) fn stage0_unphantom<A>(a: A) -> A { a }
34+
1335
extern "Rust" {
1436
// These are the magic symbols to call the global allocator. rustc generates
1537
// them from the `#[global_allocator]` attribute if there is one, or uses the
@@ -37,10 +59,14 @@ extern "Rust" {
3759
///
3860
/// Note: while this type is unstable, the functionality it provides can be
3961
/// accessed through the [free functions in `alloc`](index.html#functions).
62+
#[cfg(not(test))]
4063
#[unstable(feature = "allocator_api", issue = "32838")]
4164
#[derive(Copy, Clone, Default, Debug)]
4265
pub struct Global;
4366

67+
#[cfg(test)]
68+
pub use std::alloc::Global;
69+
4470
/// Allocate memory with the global allocator.
4571
///
4672
/// This function forwards calls to the [`GlobalAlloc::alloc`] method
@@ -144,6 +170,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
144170
__rust_alloc_zeroed(layout.size(), layout.align())
145171
}
146172

173+
#[cfg(not(test))]
147174
#[unstable(feature = "allocator_api", issue = "32838")]
148175
unsafe impl Alloc for Global {
149176
#[inline]
@@ -182,25 +209,27 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
182209
align as *mut u8
183210
} else {
184211
let layout = Layout::from_size_align_unchecked(size, align);
185-
let ptr = alloc(layout);
186-
if !ptr.is_null() {
187-
ptr
188-
} else {
189-
handle_alloc_error(layout)
212+
match Global.alloc(layout) {
213+
Ok(ptr) => ptr.as_ptr(),
214+
Err(_) => handle_alloc_error(layout),
190215
}
191216
}
192217
}
193218

219+
#[cfg(stage0)]
220+
type BoxFreeAlloc<A> = PhantomData<A>;
221+
#[cfg(not(stage0))]
222+
type BoxFreeAlloc<A> = A;
223+
194224
#[cfg_attr(not(test), lang = "box_free")]
195225
#[inline]
196-
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
197-
let ptr = ptr.as_ptr();
198-
let size = size_of_val(&*ptr);
199-
let align = min_align_of_val(&*ptr);
200-
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
226+
pub(crate) unsafe fn box_free<T: ?Sized, A: Stage0Alloc>(ptr: Unique<T>, a: BoxFreeAlloc<A>) {
227+
let size = size_of_val(&*ptr.as_ptr());
228+
let align = min_align_of_val(&*ptr.as_ptr());
229+
// We do not allocate for Box<T, A> when T is ZST, so deallocation is also not necessary.
201230
if size != 0 {
202231
let layout = Layout::from_size_align_unchecked(size, align);
203-
dealloc(ptr as *mut u8, layout);
232+
stage0_unphantom(a).dealloc(NonNull::from(ptr).cast(), layout);
204233
}
205234
}
206235

0 commit comments

Comments
 (0)