Skip to content

Commit 5d0137e

Browse files
committed
Inline Arc and Rc dealloc for T: !Drop
This avoids creating and calling `drop_slow` when all it does is decrement the weak count and potentially dealloc, which should not generate much code.
1 parent 349bda2 commit 5d0137e

File tree

2 files changed

+29
-12
lines changed

2 files changed

+29
-12
lines changed

library/alloc/src/rc.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,17 @@ impl<T: ?Sized> Rc<T> {
348348
unsafe fn from_ptr(ptr: *mut RcBox<T>) -> Self {
349349
unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
350350
}
351+
352+
// Non-inlined part of `drop`.
353+
#[inline(never)]
354+
unsafe fn drop_slow(&mut self) {
355+
// Destroy the data at this time, even though we must not free the box
356+
// allocation itself (there might still be weak pointers lying around).
357+
unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
358+
359+
// Drop the weak ref collectively held by all strong references.
360+
drop(Weak { ptr: self.ptr });
361+
}
351362
}
352363

353364
impl<T> Rc<T> {
@@ -1516,20 +1527,19 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
15161527
/// drop(foo); // Doesn't print anything
15171528
/// drop(foo2); // Prints "dropped!"
15181529
/// ```
1530+
#[inline]
15191531
fn drop(&mut self) {
15201532
unsafe {
15211533
self.inner().dec_strong();
1522-
if self.inner().strong() == 0 {
1523-
// destroy the contained object
1524-
ptr::drop_in_place(Self::get_mut_unchecked(self));
1525-
1526-
// remove the implicit "strong weak" pointer now that we've
1527-
// destroyed the contents.
1528-
self.inner().dec_weak();
1534+
if self.inner().strong() != 0 {
1535+
return;
1536+
}
15291537

1530-
if self.inner().weak() == 0 {
1531-
Global.deallocate(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
1532-
}
1538+
if mem::needs_drop::<T>() {
1539+
self.drop_slow();
1540+
} else {
1541+
// Drop the weak ref collectively held by all strong references.
1542+
drop(Weak { ptr: self.ptr });
15331543
}
15341544
}
15351545
}
@@ -2457,6 +2467,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
24572467
///
24582468
/// assert!(other_weak_foo.upgrade().is_none());
24592469
/// ```
2470+
#[inline]
24602471
fn drop(&mut self) {
24612472
let inner = if let Some(inner) = self.inner() { inner } else { return };
24622473

library/alloc/src/sync.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,7 +1105,7 @@ impl<T: ?Sized> Arc<T> {
11051105
// allocation itself (there might still be weak pointers lying around).
11061106
unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
11071107

1108-
// Drop the weak ref collectively held by all strong references
1108+
// Drop the weak ref collectively held by all strong references.
11091109
drop(Weak { ptr: self.ptr });
11101110
}
11111111

@@ -1699,7 +1699,12 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc<T> {
16991699
acquire!(self.inner().strong);
17001700

17011701
unsafe {
1702-
self.drop_slow();
1702+
if mem::needs_drop::<T>() {
1703+
self.drop_slow();
1704+
} else {
1705+
// Drop the weak ref collectively held by all strong references.
1706+
drop(Weak { ptr: self.ptr });
1707+
}
17031708
}
17041709
}
17051710
}
@@ -2159,6 +2164,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
21592164
///
21602165
/// assert!(other_weak_foo.upgrade().is_none());
21612166
/// ```
2167+
#[inline]
21622168
fn drop(&mut self) {
21632169
// If we find out that we were the last weak pointer, then its time to
21642170
// deallocate the data entirely. See the discussion in Arc::drop() about

0 commit comments

Comments
 (0)