Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions library/alloc/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ unsafe extern "Rust" {
#[rustc_deallocator]
#[rustc_nounwind]
#[rustc_std_internal_symbol]
fn __rust_dealloc(ptr: *mut u8, size: usize, align: Alignment);
fn __rust_dealloc(ptr: NonNull<u8>, size: usize, align: Alignment);
#[rustc_reallocator]
#[rustc_nounwind]
#[rustc_std_internal_symbol]
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: Alignment, new_size: usize) -> *mut u8;
fn __rust_realloc(
ptr: NonNull<u8>,
old_size: usize,
align: Alignment,
new_size: usize,
) -> *mut u8;
#[rustc_allocator_zeroed]
#[rustc_nounwind]
#[rustc_std_internal_symbol]
Expand Down Expand Up @@ -112,6 +117,13 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
unsafe { dealloc_nonnull(NonNull::new_unchecked(ptr), layout) }
}

/// Same as [`dealloc`] but when you already have a non-null pointer
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn dealloc_nonnull(ptr: NonNull<u8>, layout: Layout) {
unsafe { __rust_dealloc(ptr, layout.size(), layout.alignment()) }
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth it to manually inline these functions. They are tiny and not even encapsulating any unsafeness or tricky logic. Would make optimizations slightly faster and backtraces slightly shorter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect that it's already disappeared in the shipped liballoc rlib since the mir inliner should have done that for us already. So it would remove a inlined entry in the mir scopes, but that's it, afaict.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MIR inlined calls do still show in backtraces.


Expand All @@ -132,6 +144,13 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
unsafe { realloc_nonnull(NonNull::new_unchecked(ptr), layout, new_size) }
}

/// Same as [`realloc`] but when you already have a non-null pointer
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn realloc_nonnull(ptr: NonNull<u8>, layout: Layout, new_size: usize) -> *mut u8 {
unsafe { __rust_realloc(ptr, layout.size(), layout.alignment(), new_size) }
}

Expand Down Expand Up @@ -206,7 +225,7 @@ impl Global {
// allocation than requested.
// * Other conditions must be upheld by the caller, as per `Allocator::deallocate()`'s
// safety documentation.
unsafe { dealloc(ptr.as_ptr(), layout) }
unsafe { dealloc_nonnull(ptr, layout) }
}
}

Expand Down Expand Up @@ -236,7 +255,7 @@ impl Global {
// `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
hint::assert_unchecked(new_size >= old_layout.size());

let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
let raw_ptr = realloc_nonnull(ptr, old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
if zeroed {
raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
Expand Down Expand Up @@ -285,7 +304,7 @@ impl Global {
// `realloc` probably checks for `new_size <= old_layout.size()` or something similar.
hint::assert_unchecked(new_size <= old_layout.size());

let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
let raw_ptr = realloc_nonnull(ptr, old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::slice_from_raw_parts(ptr, new_size))
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
scope 17 (inlined Layout::size) {
}
scope 18 (inlined std::ptr::Unique::<[u8; 1024]>::cast::<u8>) {
let mut _3: std::ptr::NonNull<u8>;
scope 19 (inlined NonNull::<[u8; 1024]>::cast::<u8>) {
let mut _3: *mut u8;
scope 20 (inlined NonNull::<[u8; 1024]>::as_ptr) {
}
}
Expand All @@ -27,12 +27,10 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
scope 26 (inlined Layout::size) {
}
scope 27 (inlined NonNull::<u8>::as_ptr) {
}
scope 28 (inlined std::alloc::dealloc) {
scope 29 (inlined Layout::size) {
scope 27 (inlined alloc::alloc::dealloc_nonnull) {
scope 28 (inlined Layout::size) {
}
scope 30 (inlined Layout::alignment) {
scope 29 (inlined Layout::alignment) {
}
}
}
Expand Down Expand Up @@ -68,12 +66,14 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
}

bb0: {
StorageLive(_3);
_2 = copy (((*_1).0: std::ptr::Unique<[u8; 1024]>).0: std::ptr::NonNull<[u8; 1024]>);
_3 = copy _2 as *mut u8 (Transmute);
_3 = copy _2 as std::ptr::NonNull<u8> (Transmute);
_4 = alloc::alloc::__rust_dealloc(move _3, const 1024_usize, const std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }}) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_3);
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
scope 17 (inlined Layout::size) {
}
scope 18 (inlined std::ptr::Unique::<[u8; 1024]>::cast::<u8>) {
let mut _3: std::ptr::NonNull<u8>;
scope 19 (inlined NonNull::<[u8; 1024]>::cast::<u8>) {
let mut _3: *mut u8;
scope 20 (inlined NonNull::<[u8; 1024]>::as_ptr) {
}
}
Expand All @@ -27,12 +27,10 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
scope 26 (inlined Layout::size) {
}
scope 27 (inlined NonNull::<u8>::as_ptr) {
}
scope 28 (inlined std::alloc::dealloc) {
scope 29 (inlined Layout::size) {
scope 27 (inlined alloc::alloc::dealloc_nonnull) {
scope 28 (inlined Layout::size) {
}
scope 30 (inlined Layout::alignment) {
scope 29 (inlined Layout::alignment) {
}
}
}
Expand Down Expand Up @@ -68,12 +66,14 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () {
}

bb0: {
StorageLive(_3);
_2 = copy (((*_1).0: std::ptr::Unique<[u8; 1024]>).0: std::ptr::NonNull<[u8; 1024]>);
_3 = copy _2 as *mut u8 (Transmute);
_3 = copy _2 as std::ptr::NonNull<u8> (Transmute);
_4 = alloc::alloc::__rust_dealloc(move _3, const 1024_usize, const std::ptr::Alignment {{ _inner_repr_trick: std::ptr::alignment::AlignmentEnum::_Align1Shl0 }}) -> [return: bb1, unwind unreachable];
}

bb1: {
StorageDead(_3);
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ fn drop_generic(_1: *mut Box<T>) -> () {
scope 17 (inlined Layout::size) {
}
scope 18 (inlined std::ptr::Unique::<T>::cast::<u8>) {
let mut _4: std::ptr::NonNull<u8>;
scope 19 (inlined NonNull::<T>::cast::<u8>) {
let mut _4: *mut u8;
scope 20 (inlined NonNull::<T>::as_ptr) {
}
}
Expand All @@ -27,12 +27,10 @@ fn drop_generic(_1: *mut Box<T>) -> () {
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
scope 26 (inlined Layout::size) {
}
scope 27 (inlined NonNull::<u8>::as_ptr) {
}
scope 28 (inlined std::alloc::dealloc) {
scope 29 (inlined Layout::size) {
scope 27 (inlined alloc::alloc::dealloc_nonnull) {
scope 28 (inlined Layout::size) {
}
scope 30 (inlined Layout::alignment) {
scope 29 (inlined Layout::alignment) {
}
}
}
Expand Down Expand Up @@ -69,13 +67,14 @@ fn drop_generic(_1: *mut Box<T>) -> () {
}

bb0: {
StorageLive(_4);
_2 = copy (((*_1).0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>);
_3 = const <T as std::mem::SizedTypeProperties>::ALIGN as std::ptr::Alignment (Transmute);
switchInt(const <T as std::mem::SizedTypeProperties>::SIZE) -> [0: bb3, otherwise: bb1];
}

bb1: {
_4 = copy _2 as *mut u8 (Transmute);
_4 = copy _2 as std::ptr::NonNull<u8> (Transmute);
switchInt(const <T as std::mem::SizedTypeProperties>::SIZE) -> [0: bb3, otherwise: bb2];
}

Expand All @@ -84,6 +83,7 @@ fn drop_generic(_1: *mut Box<T>) -> () {
}

bb3: {
StorageDead(_4);
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ fn drop_generic(_1: *mut Box<T>) -> () {
scope 17 (inlined Layout::size) {
}
scope 18 (inlined std::ptr::Unique::<T>::cast::<u8>) {
let mut _4: std::ptr::NonNull<u8>;
scope 19 (inlined NonNull::<T>::cast::<u8>) {
let mut _4: *mut u8;
scope 20 (inlined NonNull::<T>::as_ptr) {
}
}
Expand All @@ -27,12 +27,10 @@ fn drop_generic(_1: *mut Box<T>) -> () {
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
scope 26 (inlined Layout::size) {
}
scope 27 (inlined NonNull::<u8>::as_ptr) {
}
scope 28 (inlined std::alloc::dealloc) {
scope 29 (inlined Layout::size) {
scope 27 (inlined alloc::alloc::dealloc_nonnull) {
scope 28 (inlined Layout::size) {
}
scope 30 (inlined Layout::alignment) {
scope 29 (inlined Layout::alignment) {
}
}
}
Expand Down Expand Up @@ -69,13 +67,14 @@ fn drop_generic(_1: *mut Box<T>) -> () {
}

bb0: {
StorageLive(_4);
_2 = copy (((*_1).0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>);
_3 = const <T as std::mem::SizedTypeProperties>::ALIGN as std::ptr::Alignment (Transmute);
switchInt(const <T as std::mem::SizedTypeProperties>::SIZE) -> [0: bb3, otherwise: bb1];
}

bb1: {
_4 = copy _2 as *mut u8 (Transmute);
_4 = copy _2 as std::ptr::NonNull<u8> (Transmute);
switchInt(const <T as std::mem::SizedTypeProperties>::SIZE) -> [0: bb3, otherwise: bb2];
}

Expand All @@ -84,6 +83,7 @@ fn drop_generic(_1: *mut Box<T>) -> () {
}

bb3: {
StorageDead(_4);
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
let _2: std::ptr::NonNull<[T]>;
let mut _3: *mut [T];
let mut _4: *const [T];
let _10: ();
let _9: ();
scope 3 {
scope 4 {
scope 17 (inlined Layout::size) {
Expand All @@ -28,15 +28,12 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
scope 24 (inlined std::alloc::Global::deallocate_impl) {
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
let mut _9: *mut u8;
scope 26 (inlined Layout::size) {
}
scope 27 (inlined NonNull::<u8>::as_ptr) {
}
scope 28 (inlined std::alloc::dealloc) {
scope 29 (inlined Layout::size) {
scope 27 (inlined alloc::alloc::dealloc_nonnull) {
scope 28 (inlined Layout::size) {
}
scope 30 (inlined Layout::alignment) {
scope 29 (inlined Layout::alignment) {
}
}
}
Expand Down Expand Up @@ -87,25 +84,18 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
bb1: {
_6 = const <T as std::mem::SizedTypeProperties>::ALIGN as std::ptr::Alignment (Transmute);
StorageDead(_4);
switchInt(copy _5) -> [0: bb4, otherwise: bb2];
switchInt(copy _5) -> [0: bb3, otherwise: bb2];
}

bb2: {
StorageLive(_7);
_7 = copy _3 as *mut u8 (PtrToPtr);
_8 = copy _7 as std::ptr::NonNull<u8> (Transmute);
StorageDead(_7);
StorageLive(_9);
_9 = copy _8 as *mut u8 (Transmute);
_10 = alloc::alloc::__rust_dealloc(move _9, move _5, move _6) -> [return: bb3, unwind unreachable];
_9 = alloc::alloc::__rust_dealloc(move _8, move _5, move _6) -> [return: bb3, unwind unreachable];
Comment on lines -98 to +95
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notably, this lets us avoid the transmute back from NonNull to *mut.

All the alloc code is doing the NonNull conversion in practice anyway, as it's using https://doc.rust-lang.org/std/alloc/struct.Global.html#method.deallocate not the alloc::dealloc function directly.

}

bb3: {
StorageDead(_9);
goto -> bb4;
}

bb4: {
StorageDead(_2);
StorageDead(_8);
StorageDead(_3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
let _2: std::ptr::NonNull<[T]>;
let mut _3: *mut [T];
let mut _4: *const [T];
let _10: ();
let _9: ();
scope 3 {
scope 4 {
scope 17 (inlined Layout::size) {
Expand All @@ -28,15 +28,12 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
scope 23 (inlined <std::alloc::Global as Allocator>::deallocate) {
scope 24 (inlined std::alloc::Global::deallocate_impl) {
scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) {
let mut _9: *mut u8;
scope 26 (inlined Layout::size) {
}
scope 27 (inlined NonNull::<u8>::as_ptr) {
}
scope 28 (inlined std::alloc::dealloc) {
scope 29 (inlined Layout::size) {
scope 27 (inlined alloc::alloc::dealloc_nonnull) {
scope 28 (inlined Layout::size) {
}
scope 30 (inlined Layout::alignment) {
scope 29 (inlined Layout::alignment) {
}
}
}
Expand Down Expand Up @@ -87,25 +84,18 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () {
bb1: {
_6 = const <T as std::mem::SizedTypeProperties>::ALIGN as std::ptr::Alignment (Transmute);
StorageDead(_4);
switchInt(copy _5) -> [0: bb4, otherwise: bb2];
switchInt(copy _5) -> [0: bb3, otherwise: bb2];
}

bb2: {
StorageLive(_7);
_7 = copy _3 as *mut u8 (PtrToPtr);
_8 = copy _7 as std::ptr::NonNull<u8> (Transmute);
StorageDead(_7);
StorageLive(_9);
_9 = copy _8 as *mut u8 (Transmute);
_10 = alloc::alloc::__rust_dealloc(move _9, move _5, move _6) -> [return: bb3, unwind unreachable];
_9 = alloc::alloc::__rust_dealloc(move _8, move _5, move _6) -> [return: bb3, unwind unreachable];
}

bb3: {
StorageDead(_9);
goto -> bb4;
}

bb4: {
StorageDead(_2);
StorageDead(_8);
StorageDead(_3);
Expand Down
Loading
Loading