Skip to content

Commit 41730b7

Browse files
committed
Rc: remove unused allocation from Weak::new()
Same as #50357
1 parent 6e2c49f commit 41730b7

File tree

2 files changed

+37
-24
lines changed

2 files changed

+37
-24
lines changed

src/liballoc/rc.rs

+36-23
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,15 @@ use core::hash::{Hash, Hasher};
253253
use core::intrinsics::abort;
254254
use core::marker;
255255
use core::marker::{Unsize, PhantomData};
256-
use core::mem::{self, align_of_val, forget, size_of_val, uninitialized};
256+
use core::mem::{self, align_of_val, forget, size_of_val};
257257
use core::ops::Deref;
258258
use core::ops::CoerceUnsized;
259259
use core::ptr::{self, NonNull};
260260
use core::convert::From;
261261

262262
use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error};
263263
use string::String;
264+
use sync::is_dangling;
264265
use vec::Vec;
265266

266267
struct RcBox<T: ?Sized> {
@@ -1153,6 +1154,10 @@ impl<T> From<Vec<T>> for Rc<[T]> {
11531154
/// [`None`]: ../../std/option/enum.Option.html#variant.None
11541155
#[stable(feature = "rc_weak", since = "1.4.0")]
11551156
pub struct Weak<T: ?Sized> {
1157+
// This is a `NonNull` to allow optimizing the size of this type in enums,
1158+
// but it is not necessarily a valid pointer.
1159+
// `Weak::new` sets this to a dangling pointer so that it doesn’t need
1160+
// to allocate space on the heap.
11561161
ptr: NonNull<RcBox<T>>,
11571162
}
11581163

@@ -1165,8 +1170,8 @@ impl<T: ?Sized> !marker::Sync for Weak<T> {}
11651170
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
11661171

11671172
impl<T> Weak<T> {
1168-
/// Constructs a new `Weak<T>`, allocating memory for `T` without initializing
1169-
/// it. Calling [`upgrade`] on the return value always gives [`None`].
1173+
/// Constructs a new `Weak<T>`, without allocating any memory.
1174+
/// Calling [`upgrade`] on the return value always gives [`None`].
11701175
///
11711176
/// [`upgrade`]: struct.Weak.html#method.upgrade
11721177
/// [`None`]: ../../std/option/enum.Option.html
@@ -1181,14 +1186,8 @@ impl<T> Weak<T> {
11811186
/// ```
11821187
#[stable(feature = "downgraded_weak", since = "1.10.0")]
11831188
pub fn new() -> Weak<T> {
1184-
unsafe {
1185-
Weak {
1186-
ptr: Box::into_raw_non_null(box RcBox {
1187-
strong: Cell::new(0),
1188-
weak: Cell::new(1),
1189-
value: uninitialized(),
1190-
}),
1191-
}
1189+
Weak {
1190+
ptr: NonNull::dangling(),
11921191
}
11931192
}
11941193
}
@@ -1222,13 +1221,25 @@ impl<T: ?Sized> Weak<T> {
12221221
/// ```
12231222
#[stable(feature = "rc_weak", since = "1.4.0")]
12241223
pub fn upgrade(&self) -> Option<Rc<T>> {
1225-
if self.strong() == 0 {
1224+
let inner = self.inner()?;
1225+
if inner.strong() == 0 {
12261226
None
12271227
} else {
1228-
self.inc_strong();
1228+
inner.inc_strong();
12291229
Some(Rc { ptr: self.ptr, phantom: PhantomData })
12301230
}
12311231
}
1232+
1233+
/// Return `None` when the pointer is dangling and there is no allocated `RcBox`,
1234+
/// i.e. this `Weak` was created by `Weak::new`
1235+
#[inline]
1236+
fn inner(&self) -> Option<&RcBox<T>> {
1237+
if is_dangling(self.ptr) {
1238+
None
1239+
} else {
1240+
Some(unsafe { self.ptr.as_ref() })
1241+
}
1242+
}
12321243
}
12331244

12341245
#[stable(feature = "rc_weak", since = "1.4.0")]
@@ -1258,12 +1269,14 @@ impl<T: ?Sized> Drop for Weak<T> {
12581269
/// assert!(other_weak_foo.upgrade().is_none());
12591270
/// ```
12601271
fn drop(&mut self) {
1261-
unsafe {
1262-
self.dec_weak();
1272+
if let Some(inner) = self.inner() {
1273+
inner.dec_weak();
12631274
// the weak count starts at 1, and will only go to zero if all
12641275
// the strong pointers have disappeared.
1265-
if self.weak() == 0 {
1266-
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
1276+
if inner.weak() == 0 {
1277+
unsafe {
1278+
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
1279+
}
12671280
}
12681281
}
12691282
}
@@ -1284,7 +1297,9 @@ impl<T: ?Sized> Clone for Weak<T> {
12841297
/// ```
12851298
#[inline]
12861299
fn clone(&self) -> Weak<T> {
1287-
self.inc_weak();
1300+
if let Some(inner) = self.inner() {
1301+
inner.inc_weak()
1302+
}
12881303
Weak { ptr: self.ptr }
12891304
}
12901305
}
@@ -1317,7 +1332,7 @@ impl<T> Default for Weak<T> {
13171332
}
13181333
}
13191334

1320-
// NOTE: We checked_add here to deal with mem::forget safety. In particular
1335+
// NOTE: We checked_add here to deal with mem::forget safely. In particular
13211336
// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then
13221337
// you can free the allocation while outstanding Rcs (or Weaks) exist.
13231338
// We abort because this is such a degenerate scenario that we don't care about
@@ -1370,12 +1385,10 @@ impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
13701385
}
13711386
}
13721387

1373-
impl<T: ?Sized> RcBoxPtr<T> for Weak<T> {
1388+
impl<T: ?Sized> RcBoxPtr<T> for RcBox<T> {
13741389
#[inline(always)]
13751390
fn inner(&self) -> &RcBox<T> {
1376-
unsafe {
1377-
self.ptr.as_ref()
1378-
}
1391+
self
13791392
}
13801393
}
13811394

src/liballoc/sync.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ impl<T> Weak<T> {
10381038
}
10391039
}
10401040

1041-
fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
1041+
pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
10421042
let address = ptr.as_ptr() as *mut () as usize;
10431043
let align = align_of_val(unsafe { ptr.as_ref() });
10441044
address == align

0 commit comments

Comments
 (0)