Specialize Box clones to try to avoid locals
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.
This commit is contained in:
parent
fe531d5a5f
commit
9aa7dd1e6a
@ -1014,10 +1014,14 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
|
|||||||
/// // But they are unique objects
|
/// // But they are unique objects
|
||||||
/// assert_ne!(&*x as *const i32, &*y as *const i32);
|
/// assert_ne!(&*x as *const i32, &*y as *const i32);
|
||||||
/// ```
|
/// ```
|
||||||
#[rustfmt::skip]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn clone(&self) -> Self {
|
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.
|
/// Copies `source`'s contents into `self` without creating a new allocation.
|
||||||
@ -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")]
|
#[stable(feature = "box_slice_clone", since = "1.3.0")]
|
||||||
impl Clone for Box<str> {
|
impl Clone for Box<str> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user