Skip to content

Commit d85df44

Browse files
committed
Specialize Rc/Arc::make_mut clones to try to avoid locals
As we did with `Box`, we can allocate an uninitialized `Rc` or `Arc` beforehand, giving the optimizer a chance to skip the local value for regular clones, or avoid any local altogether for `T: Copy`.
1 parent 9aa7dd1 commit d85df44

File tree

2 files changed

+18
-5
lines changed

2 files changed

+18
-5
lines changed

library/alloc/src/rc.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ use core::slice::from_raw_parts_mut;
265265

266266
use crate::alloc::{box_free, handle_alloc_error, AllocError, Allocator, Global, Layout};
267267
use crate::borrow::{Cow, ToOwned};
268+
use crate::boxed::WriteCloneIntoRaw;
268269
use crate::string::String;
269270
use crate::vec::Vec;
270271

@@ -1037,8 +1038,14 @@ impl<T: Clone> Rc<T> {
10371038
#[stable(feature = "rc_unique", since = "1.4.0")]
10381039
pub fn make_mut(this: &mut Self) -> &mut T {
10391040
if Rc::strong_count(this) != 1 {
1040-
// Gotta clone the data, there are other Rcs
1041-
*this = Rc::new((**this).clone())
1041+
// Gotta clone the data, there are other Rcs.
1042+
// Pre-allocate memory to allow writing the cloned value directly.
1043+
let mut rc = Self::new_uninit();
1044+
unsafe {
1045+
let data = Rc::get_mut_unchecked(&mut rc);
1046+
(**this).write_clone_into_raw(data.as_mut_ptr());
1047+
*this = rc.assume_init();
1048+
}
10421049
} else if Rc::weak_count(this) != 0 {
10431050
// Can just steal the data, all that's left is Weaks
10441051
unsafe {

library/alloc/src/sync.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
2424

2525
use crate::alloc::{box_free, handle_alloc_error, AllocError, Allocator, Global, Layout};
2626
use crate::borrow::{Cow, ToOwned};
27-
use crate::boxed::Box;
27+
use crate::boxed::{Box, WriteCloneIntoRaw};
2828
use crate::rc::is_dangling;
2929
use crate::string::String;
3030
use crate::vec::Vec;
@@ -1369,8 +1369,14 @@ impl<T: Clone> Arc<T> {
13691369
// weak count, there's no chance the ArcInner itself could be
13701370
// deallocated.
13711371
if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() {
1372-
// Another strong pointer exists; clone
1373-
*this = Arc::new((**this).clone());
1372+
// Another strong pointer exists, so we must clone.
1373+
// Pre-allocate memory to allow writing the cloned value directly.
1374+
let mut arc = Self::new_uninit();
1375+
unsafe {
1376+
let data = Arc::get_mut_unchecked(&mut arc);
1377+
(**this).write_clone_into_raw(data.as_mut_ptr());
1378+
*this = arc.assume_init();
1379+
}
13741380
} else if this.inner().weak.load(Relaxed) != 1 {
13751381
// Relaxed suffices in the above because this is fundamentally an
13761382
// optimization: we are always racing with weak pointers being

0 commit comments

Comments
 (0)