Skip to content

Commit

Permalink
Specialize Box clones to try to avoid locals
Browse files Browse the repository at this point in the history
For generic `T: Clone`, we can allocate an uninitialized box beforehand,
which gives the optimizer a chance to create the clone directly in the
heap. For `T: Copy`, we can go further and do a simple memory copy,
regardless of optimization level.
  • Loading branch information
cuviper committed Jan 12, 2021
1 parent fe531d5 commit 9aa7dd1
Showing 1 changed file with 28 additions and 2 deletions.
30 changes: 28 additions & 2 deletions library/alloc/src/boxed.rs
Expand Up @@ -1014,10 +1014,14 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
/// // But they are unique objects
/// assert_ne!(&*x as *const i32, &*y as *const i32);
/// ```
#[rustfmt::skip]
#[inline]
fn clone(&self) -> Self {
Self::new_in((**self).clone(), self.1.clone())
// Pre-allocate memory to allow writing the cloned value directly.
let mut boxed = Self::new_uninit_in(self.1.clone());
unsafe {
(**self).write_clone_into_raw(boxed.as_mut_ptr());
boxed.assume_init()
}
}

/// Copies `source`'s contents into `self` without creating a new allocation.
Expand All @@ -1043,6 +1047,28 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
}
}

/// Specialize clones into pre-allocated, uninitialized memory.
pub(crate) trait WriteCloneIntoRaw: Sized {
unsafe fn write_clone_into_raw(&self, target: *mut Self);
}

impl<T: Clone> WriteCloneIntoRaw for T {
#[inline]
default unsafe fn write_clone_into_raw(&self, target: *mut Self) {
// Having allocated *first* may allow the optimizer to create
// the cloned value in-place, skipping the local and move.
unsafe { target.write(self.clone()) };
}
}

impl<T: Copy> WriteCloneIntoRaw for T {
#[inline]
unsafe fn write_clone_into_raw(&self, target: *mut Self) {
// We can always copy in-place, without ever involving a local value.
unsafe { target.copy_from_nonoverlapping(self, 1) };
}
}

#[stable(feature = "box_slice_clone", since = "1.3.0")]
impl Clone for Box<str> {
fn clone(&self) -> Self {
Expand Down

0 comments on commit 9aa7dd1

Please sign in to comment.