Skip to content

Commit be0ade2

Browse files
committed
Auto merge of #147124 - a1phyr:improve_finish_grow, r=Mark-Simulacrum
Move more code to `RawVec::finish_grow` This move a branch and more code into the cold method `finish_grow`, which means that less code is inlined at each `try_reserve` site. Additionally, this reduces the amount of parameters, so they can all be passed by registers.
2 parents 360a3a4 + e52fe65 commit be0ade2

File tree

1 file changed

+40
-55
lines changed
  • library/alloc/src/raw_vec

1 file changed

+40
-55
lines changed

library/alloc/src/raw_vec/mod.rs

Lines changed: 40 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -668,8 +668,7 @@ impl<A: Allocator> RawVecInner<A> {
668668
/// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
669669
/// initially construct `self`
670670
/// - `elem_layout`'s size must be a multiple of its alignment
671-
/// - The sum of `len` and `additional` must be greater than or equal to
672-
/// `self.capacity(elem_layout.size())`
671+
/// - The sum of `len` and `additional` must be greater than the current capacity
673672
unsafe fn grow_amortized(
674673
&mut self,
675674
len: usize,
@@ -693,16 +692,12 @@ impl<A: Allocator> RawVecInner<A> {
693692
let cap = cmp::max(self.cap.as_inner() * 2, required_cap);
694693
let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap);
695694

696-
let new_layout = layout_array(cap, elem_layout)?;
697-
698695
// SAFETY:
699-
// - For the `current_memory` call: Precondition passed to caller
700-
// - For the `finish_grow` call: Precondition passed to caller
701-
// + `current_memory` does the right thing
702-
let ptr =
703-
unsafe { finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)? };
696+
// - cap >= len + additional
697+
// - other preconditions passed to caller
698+
let ptr = unsafe { self.finish_grow(cap, elem_layout)? };
704699

705-
// SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
700+
// SAFETY: `finish_grow` would have failed if `cap > isize::MAX`
706701
unsafe { self.set_ptr_and_cap(ptr, cap) };
707702
Ok(())
708703
}
@@ -711,8 +706,7 @@ impl<A: Allocator> RawVecInner<A> {
711706
/// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
712707
/// initially construct `self`
713708
/// - `elem_layout`'s size must be a multiple of its alignment
714-
/// - The sum of `len` and `additional` must be greater than or equal to
715-
/// `self.capacity(elem_layout.size())`
709+
/// - The sum of `len` and `additional` must be greater than the current capacity
716710
unsafe fn grow_exact(
717711
&mut self,
718712
len: usize,
@@ -726,21 +720,44 @@ impl<A: Allocator> RawVecInner<A> {
726720
}
727721

728722
let cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
729-
let new_layout = layout_array(cap, elem_layout)?;
730723

731-
// SAFETY:
732-
// - For the `current_memory` call: Precondition passed to caller
733-
// - For the `finish_grow` call: Precondition passed to caller
734-
// + `current_memory` does the right thing
735-
let ptr =
736-
unsafe { finish_grow(new_layout, self.current_memory(elem_layout), &mut self.alloc)? };
737-
// SAFETY: layout_array would have resulted in a capacity overflow if we tried to allocate more than `isize::MAX` items
738-
unsafe {
739-
self.set_ptr_and_cap(ptr, cap);
740-
}
724+
// SAFETY: preconditions passed to caller
725+
let ptr = unsafe { self.finish_grow(cap, elem_layout)? };
726+
727+
// SAFETY: `finish_grow` would have failed if `cap > isize::MAX`
728+
unsafe { self.set_ptr_and_cap(ptr, cap) };
741729
Ok(())
742730
}
743731

732+
/// # Safety
733+
/// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
734+
/// initially construct `self`
735+
/// - `elem_layout`'s size must be a multiple of its alignment
736+
/// - `cap` must be greater than the current capacity
737+
// not marked inline(never) since we want optimizers to be able to observe the specifics of this
738+
// function, see tests/codegen-llvm/vec-reserve-extend.rs.
739+
#[cold]
740+
unsafe fn finish_grow(
741+
&self,
742+
cap: usize,
743+
elem_layout: Layout,
744+
) -> Result<NonNull<[u8]>, TryReserveError> {
745+
let new_layout = layout_array(cap, elem_layout)?;
746+
747+
let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } {
748+
debug_assert_eq!(old_layout.align(), new_layout.align());
749+
unsafe {
750+
// The allocator checks for alignment equality
751+
hint::assert_unchecked(old_layout.align() == new_layout.align());
752+
self.alloc.grow(ptr, old_layout, new_layout)
753+
}
754+
} else {
755+
self.alloc.allocate(new_layout)
756+
};
757+
758+
memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into())
759+
}
760+
744761
/// # Safety
745762
/// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to
746763
/// initially construct `self`
@@ -820,38 +837,6 @@ impl<A: Allocator> RawVecInner<A> {
820837
}
821838
}
822839

823-
/// # Safety
824-
/// If `current_memory` matches `Some((ptr, old_layout))`:
825-
/// - `ptr` must denote a block of memory *currently allocated* via `alloc`
826-
/// - `old_layout` must *fit* that block of memory
827-
/// - `new_layout` must have the same alignment as `old_layout`
828-
/// - `new_layout.size()` must be greater than or equal to `old_layout.size()`
829-
/// If `current_memory` is `None`, this function is safe.
830-
// not marked inline(never) since we want optimizers to be able to observe the specifics of this
831-
// function, see tests/codegen-llvm/vec-reserve-extend.rs.
832-
#[cold]
833-
unsafe fn finish_grow<A>(
834-
new_layout: Layout,
835-
current_memory: Option<(NonNull<u8>, Layout)>,
836-
alloc: &mut A,
837-
) -> Result<NonNull<[u8]>, TryReserveError>
838-
where
839-
A: Allocator,
840-
{
841-
let memory = if let Some((ptr, old_layout)) = current_memory {
842-
debug_assert_eq!(old_layout.align(), new_layout.align());
843-
unsafe {
844-
// The allocator checks for alignment equality
845-
hint::assert_unchecked(old_layout.align() == new_layout.align());
846-
alloc.grow(ptr, old_layout, new_layout)
847-
}
848-
} else {
849-
alloc.allocate(new_layout)
850-
};
851-
852-
memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into())
853-
}
854-
855840
// Central function for reserve error handling.
856841
#[cfg(not(no_global_oom_handling))]
857842
#[cold]

0 commit comments

Comments
 (0)