diff options
| author | Amanieu d'Antras <amanieu@gmail.com> | 2023-06-27 23:33:44 +0100 |
|---|---|---|
| committer | Amanieu d'Antras <amanieu@gmail.com> | 2023-07-13 15:00:53 +0100 |
| commit | d24be14276bc5e52c6ab42d29ab2ed717b2b583c (patch) | |
| tree | 33495ab7756dba351e99a5b8249585cf5b78669d /library/alloc/src | |
| parent | 27e10c5292eee22abef69aed7144f80bdea00603 (diff) | |
Eliminate ZST allocations in `Box` and `Vec`
Diffstat (limited to 'library/alloc/src')
| -rw-r--r-- | library/alloc/src/boxed.rs | 44 | ||||
| -rw-r--r-- | library/alloc/src/raw_vec.rs | 30 |
2 files changed, 49 insertions, 25 deletions
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 8ef2bac9282..8697a77db3b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -157,12 +157,12 @@ use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::Tuple; use core::marker::Unsize; -use core::mem; +use core::mem::{self, SizedTypeProperties}; use core::ops::{ CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver, }; use core::pin::Pin; -use core::ptr::{self, Unique}; +use core::ptr::{self, NonNull, Unique}; use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] @@ -479,8 +479,12 @@ impl<T, A: Allocator> Box<T, A> { where A: Allocator, { - let layout = Layout::new::<mem::MaybeUninit<T>>(); - let ptr = alloc.allocate(layout)?.cast(); + let ptr = if T::IS_ZST { + NonNull::dangling() + } else { + let layout = Layout::new::<mem::MaybeUninit<T>>(); + alloc.allocate(layout)?.cast() + }; unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } } @@ -549,8 +553,12 @@ impl<T, A: Allocator> Box<T, A> { where A: Allocator, { - let layout = Layout::new::<mem::MaybeUninit<T>>(); - let ptr = alloc.allocate_zeroed(layout)?.cast(); + let ptr = if T::IS_ZST { + NonNull::dangling() + } else { + let layout = Layout::new::<mem::MaybeUninit<T>>(); + alloc.allocate_zeroed(layout)?.cast() + }; unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) } } @@ -675,14 +683,16 @@ impl<T> Box<[T]> { #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> { - unsafe { + let ptr = if T::IS_ZST || len == 0 { + NonNull::dangling() + } else { let layout = match Layout::array::<mem::MaybeUninit<T>>(len) { Ok(l) => l, Err(_) => return Err(AllocError), }; - let ptr = Global.allocate(layout)?; - Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) - } + Global.allocate(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) } } /// Constructs a new boxed slice with uninitialized contents, with the memory @@ -707,14 +717,16 @@ impl<T> Box<[T]> { #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn try_new_zeroed_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> { - unsafe { + let ptr = if T::IS_ZST || len == 0 { + NonNull::dangling() + } else { let layout = match Layout::array::<mem::MaybeUninit<T>>(len) { Ok(l) => l, Err(_) => return Err(AllocError), }; - let ptr = Global.allocate_zeroed(layout)?; - Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) - } + Global.allocate_zeroed(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) } } } @@ -1219,7 +1231,9 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> { unsafe { let layout = Layout::for_value_raw(ptr.as_ptr()); - self.1.deallocate(From::from(ptr.cast()), layout) + if layout.size() != 0 { + self.1.deallocate(From::from(ptr.cast()), layout); + } } } } diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index dfd30d99cf0..01b03de6acb 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -432,16 +432,26 @@ impl<T, A: Allocator> RawVec<T, A> { let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; // See current_memory() why this assert is here let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) }; - let ptr = unsafe { - // `Layout::array` cannot overflow here because it would have - // overflowed earlier when capacity was larger. - let new_size = mem::size_of::<T>().unchecked_mul(cap); - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc - .shrink(ptr, layout, new_layout) - .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? - }; - self.set_ptr_and_cap(ptr, cap); + + // If shrinking to 0, deallocate the buffer. We don't reach this point + // for the T::IS_ZST case since current_memory() will have returned + // None. + if cap == 0 { + unsafe { self.alloc.deallocate(ptr, layout) }; + self.ptr = Unique::dangling(); + self.cap = 0; + } else { + let ptr = unsafe { + // `Layout::array` cannot overflow here because it would have + // overflowed earlier when capacity was larger. + let new_size = mem::size_of::<T>().unchecked_mul(cap); + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + self.alloc + .shrink(ptr, layout, new_layout) + .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? + }; + self.set_ptr_and_cap(ptr, cap); + } Ok(()) } } |
