Skip to content

Commit

Permalink
Auto merge of rust-lang#107167 - the8472:rawvec-simpler-layout, r=thomcc
Browse files Browse the repository at this point in the history
simplify layout calculations in rawvec

The use of `Layout::array` was introduced in rust-lang#83706 which lead to a [perf regression](rust-lang#83706 (comment)).

This PR basically reverts that change since rust currently only supports stride == size types, but to be on the safe side it leaves a const-assert there to make sure this gets caught if those assumptions ever change.
  • Loading branch information
bors committed Feb 11, 2023
2 parents 5b45024 + 6fcf175 commit 8dabf5d
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 6 deletions.
17 changes: 12 additions & 5 deletions library/alloc/src/raw_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,15 @@ impl<T, A: Allocator> RawVec<T, A> {
if T::IS_ZST || self.cap == 0 {
None
} else {
// We have an allocated chunk of memory, so we can bypass runtime
// checks to get our current layout.
// We could use Layout::array here which ensures the absence of isize and usize overflows
// and could hypothetically handle differences between stride and size, but this memory
// has already been allocated so we know it can't overflow and currently rust does not
// support such types. So we can do better by skipping some checks and avoid an unwrap.
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
unsafe {
let layout = Layout::array::<T>(self.cap).unwrap_unchecked();
let align = mem::align_of::<T>();
let size = mem::size_of::<T>().unchecked_mul(self.cap);
let layout = Layout::from_size_align_unchecked(size, align);
Some((self.ptr.cast().into(), layout))
}
}
Expand Down Expand Up @@ -426,11 +431,13 @@ impl<T, A: Allocator> RawVec<T, A> {
assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity");

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_layout = Layout::array::<T>(cap).unwrap_unchecked();
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: () })?
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/hygiene/panic-location.run.stderr
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
thread 'main' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:518:5
thread 'main' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:525:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

0 comments on commit 8dabf5d

Please sign in to comment.