Skip to content

Commit 8dabf5d

Browse files
committed
Auto merge of rust-lang#107167 - the8472:rawvec-simpler-layout, r=thomcc
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.
2 parents 5b45024 + 6fcf175 commit 8dabf5d

File tree

2 files changed

+13
-6
lines changed

2 files changed

+13
-6
lines changed

library/alloc/src/raw_vec.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,15 @@ impl<T, A: Allocator> RawVec<T, A> {
241241
if T::IS_ZST || self.cap == 0 {
242242
None
243243
} else {
244-
// We have an allocated chunk of memory, so we can bypass runtime
245-
// checks to get our current layout.
244+
// We could use Layout::array here which ensures the absence of isize and usize overflows
245+
// and could hypothetically handle differences between stride and size, but this memory
246+
// has already been allocated so we know it can't overflow and currently rust does not
247+
// support such types. So we can do better by skipping some checks and avoid an unwrap.
248+
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
246249
unsafe {
247-
let layout = Layout::array::<T>(self.cap).unwrap_unchecked();
250+
let align = mem::align_of::<T>();
251+
let size = mem::size_of::<T>().unchecked_mul(self.cap);
252+
let layout = Layout::from_size_align_unchecked(size, align);
248253
Some((self.ptr.cast().into(), layout))
249254
}
250255
}
@@ -426,11 +431,13 @@ impl<T, A: Allocator> RawVec<T, A> {
426431
assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity");
427432

428433
let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
429-
434+
// See current_memory() why this assert is here
435+
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
430436
let ptr = unsafe {
431437
// `Layout::array` cannot overflow here because it would have
432438
// overflowed earlier when capacity was larger.
433-
let new_layout = Layout::array::<T>(cap).unwrap_unchecked();
439+
let new_size = mem::size_of::<T>().unchecked_mul(cap);
440+
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
434441
self.alloc
435442
.shrink(ptr, layout, new_layout)
436443
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
thread 'main' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:518:5
1+
thread 'main' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:525:5
22
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

0 commit comments

Comments
 (0)