From 894236f66d08a7078fb8029e58882fd0a09c388b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 3 Aug 2020 18:19:51 +1000 Subject: [PATCH] Avoid `Layout::array()` in `raw_vec.rs`. A non-generic equivalent results in less LLVM IR and faster compilation. --- library/alloc/src/raw_vec.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index ed81ce71ddfac..5bb5524ecb322 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -1,7 +1,7 @@ #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")] #![doc(hidden)] -use core::alloc::{LayoutErr, MemoryBlock}; +use core::alloc::MemoryBlock; use core::cmp; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::Drop; @@ -172,7 +172,7 @@ impl RawVec { } else { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. - let layout = match Layout::array::(capacity) { + let layout = match array_layout(Layout::new::(), capacity) { Ok(layout) => layout, Err(_) => capacity_overflow(), }; @@ -423,10 +423,10 @@ impl RawVec { }; let cap = cmp::max(min_non_zero_cap, cap); - let new_layout = Layout::array::(cap); + let elem_layout = Layout::new::(); // `finish_grow` is non-generic over `T`. - let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; + let memory = finish_grow(cap, elem_layout, self.current_memory(), &mut self.alloc)?; self.set_memory(memory); Ok(()) } @@ -442,10 +442,11 @@ impl RawVec { } let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; - let new_layout = Layout::array::(cap); + + let elem_layout = Layout::new::(); // `finish_grow` is non-generic over `T`. - let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; + let memory = finish_grow(cap, elem_layout, self.current_memory(), &mut self.alloc)?; self.set_memory(memory); Ok(()) } @@ -478,7 +479,8 @@ impl RawVec { // significant, because the number of different `A` types seen in practice is // much smaller than the number of `T` types.) fn finish_grow( - new_layout: Result, + cap: usize, + elem_layout: Layout, current_memory: Option<(NonNull, Layout)>, alloc: &mut A, ) -> Result @@ -486,7 +488,7 @@ where A: AllocRef, { // Check for the error here to minimize the size of `RawVec::grow_*`. - let new_layout = new_layout.map_err(|_| CapacityOverflow)?; + let new_layout = array_layout(elem_layout, cap)?; alloc_guard(new_layout.size())?; @@ -501,6 +503,15 @@ where Ok(memory) } +// This is equivalent to Layout::array, but is non-generic and has a different +// error type in its result. It helps reduce the amount of LLVM IR generated. +#[inline] +fn array_layout(elem_layout: Layout, n: usize) -> Result { + let (new_layout, offset) = elem_layout.repeat(n).map_err(|_| CapacityOverflow)?; + debug_assert_eq!(offset, elem_layout.size()); + Ok(new_layout.pad_to_align()) +} + unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. fn drop(&mut self) {