Skip to content

Commit 5f42947

Browse files
author
Julian Orth
committed
Restructure Rc and Arc to support StructAlloc
1 parent e080a05 commit 5f42947

File tree

4 files changed

+108
-104
lines changed

4 files changed

+108
-104
lines changed

library/alloc/src/rc.rs

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,13 @@ use core::hash::{Hash, Hasher};
257257
use core::intrinsics::abort;
258258
use core::iter;
259259
use core::marker::{self, PhantomData, Unpin, Unsize};
260-
use core::mem::{self, align_of_val_raw, forget, size_of_val};
260+
use core::mem::{self, forget, size_of_val};
261261
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
262262
use core::pin::Pin;
263263
use core::ptr::{self, NonNull};
264264
use core::slice::from_raw_parts_mut;
265265

266+
use crate::alloc::struct_alloc::StructAlloc;
266267
use crate::alloc::{
267268
box_free, handle_alloc_error, AllocError, Allocator, Global, Layout, WriteCloneIntoRaw,
268269
};
@@ -273,13 +274,31 @@ use crate::vec::Vec;
273274
#[cfg(test)]
274275
mod tests;
275276

276-
// This is repr(C) to future-proof against possible field-reordering, which
277-
// would interfere with otherwise safe [into|from]_raw() of transmutable
278-
// inner types.
279-
#[repr(C)]
280-
struct RcBox<T: ?Sized> {
277+
struct RcBoxMetadata {
281278
strong: Cell<usize>,
282279
weak: Cell<usize>,
280+
}
281+
282+
impl RcBoxMetadata {
283+
// There is an implicit weak pointer owned by all the strong
284+
// pointers, which ensures that the weak destructor never frees
285+
// the allocation while the strong destructor is running, even
286+
// if the weak pointer is stored inside the strong one.
287+
#[inline]
288+
fn new_strong() -> Self {
289+
Self { strong: Cell::new(1), weak: Cell::new(1) }
290+
}
291+
292+
#[inline]
293+
fn new_weak() -> Self {
294+
Self { strong: Cell::new(0), weak: Cell::new(1) }
295+
}
296+
}
297+
298+
// This is repr(C) to support StructAlloc
299+
#[repr(C)]
300+
struct RcBox<T: ?Sized> {
301+
meta: RcBoxMetadata,
283302
value: T,
284303
}
285304

@@ -340,13 +359,7 @@ impl<T> Rc<T> {
340359
/// ```
341360
#[stable(feature = "rust1", since = "1.0.0")]
342361
pub fn new(value: T) -> Rc<T> {
343-
// There is an implicit weak pointer owned by all the strong
344-
// pointers, which ensures that the weak destructor never frees
345-
// the allocation while the strong destructor is running, even
346-
// if the weak pointer is stored inside the strong one.
347-
Self::from_inner(
348-
Box::leak(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value }).into(),
349-
)
362+
Self::from_inner(Box::leak(box RcBox { meta: RcBoxMetadata::new_strong(), value }).into())
350363
}
351364

352365
/// Constructs a new `Rc<T>` using a weak reference to itself. Attempting
@@ -378,8 +391,7 @@ impl<T> Rc<T> {
378391
// Construct the inner in the "uninitialized" state with a single
379392
// weak reference.
380393
let uninit_ptr: NonNull<_> = Box::leak(box RcBox {
381-
strong: Cell::new(0),
382-
weak: Cell::new(1),
394+
meta: RcBoxMetadata::new_weak(),
383395
value: mem::MaybeUninit::<T>::uninit(),
384396
})
385397
.into();
@@ -400,9 +412,9 @@ impl<T> Rc<T> {
400412
let inner = init_ptr.as_ptr();
401413
ptr::write(ptr::addr_of_mut!((*inner).value), data);
402414

403-
let prev_value = (*inner).strong.get();
415+
let prev_value = (*inner).meta.strong.get();
404416
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
405-
(*inner).strong.set(1);
417+
(*inner).meta.strong.set(1);
406418
}
407419

408420
let strong = Rc::from_inner(init_ptr);
@@ -489,13 +501,8 @@ impl<T> Rc<T> {
489501
/// ```
490502
#[unstable(feature = "allocator_api", issue = "32838")]
491503
pub fn try_new(value: T) -> Result<Rc<T>, AllocError> {
492-
// There is an implicit weak pointer owned by all the strong
493-
// pointers, which ensures that the weak destructor never frees
494-
// the allocation while the strong destructor is running, even
495-
// if the weak pointer is stored inside the strong one.
496504
Ok(Self::from_inner(
497-
Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?)
498-
.into(),
505+
Box::leak(Box::try_new(RcBox { meta: RcBoxMetadata::new_strong(), value })?).into(),
499506
))
500507
}
501508

@@ -1170,8 +1177,8 @@ impl<T: ?Sized> Rc<T> {
11701177
unsafe {
11711178
debug_assert_eq!(Layout::for_value(&*inner), layout);
11721179

1173-
ptr::write(&mut (*inner).strong, Cell::new(1));
1174-
ptr::write(&mut (*inner).weak, Cell::new(1));
1180+
ptr::write(&mut (*inner).meta.strong, Cell::new(1));
1181+
ptr::write(&mut (*inner).meta.weak, Cell::new(1));
11751182
}
11761183

11771184
Ok(inner)
@@ -2087,7 +2094,7 @@ impl<T: ?Sized> Weak<T> {
20872094
// is dropped, the data field will be dropped in-place).
20882095
Some(unsafe {
20892096
let ptr = self.ptr.as_ptr();
2090-
WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak }
2097+
WeakInner { strong: &(*ptr).meta.strong, weak: &(*ptr).meta.weak }
20912098
})
20922099
}
20932100
}
@@ -2296,12 +2303,12 @@ trait RcInnerPtr {
22962303
impl<T: ?Sized> RcInnerPtr for RcBox<T> {
22972304
#[inline(always)]
22982305
fn weak_ref(&self) -> &Cell<usize> {
2299-
&self.weak
2306+
&self.meta.weak
23002307
}
23012308

23022309
#[inline(always)]
23032310
fn strong_ref(&self) -> &Cell<usize> {
2304-
&self.strong
2311+
&self.meta.strong
23052312
}
23062313
}
23072314

@@ -2334,24 +2341,21 @@ impl<T: ?Sized> AsRef<T> for Rc<T> {
23342341
#[stable(feature = "pin", since = "1.33.0")]
23352342
impl<T: ?Sized> Unpin for Rc<T> {}
23362343

2344+
type RcStructAlloc = StructAlloc<RcBoxMetadata>;
2345+
23372346
/// Get the offset within an `RcBox` for the payload behind a pointer.
23382347
///
23392348
/// # Safety
23402349
///
23412350
/// The pointer must point to (and have valid metadata for) a previously
23422351
/// valid instance of T, but the T is allowed to be dropped.
2343-
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
2344-
// Align the unsized value to the end of the RcBox.
2345-
// Because RcBox is repr(C), it will always be the last field in memory.
2346-
// SAFETY: since the only unsized types possible are slices, trait objects,
2347-
// and extern types, the input safety requirement is currently enough to
2348-
// satisfy the requirements of align_of_val_raw; this is an implementation
2349-
// detail of the language that may not be relied upon outside of std.
2350-
unsafe { data_offset_align(align_of_val_raw(ptr)) }
2351-
}
2352-
2353-
#[inline]
2354-
fn data_offset_align(align: usize) -> isize {
2355-
let layout = Layout::new::<RcBox<()>>();
2356-
(layout.size() + layout.padding_needed_for(align)) as isize
2352+
unsafe fn data_offset<T: ?Sized>(data_ptr: *const T) -> isize {
2353+
unsafe {
2354+
// SAFETY: since the only unsized types possible are slices, trait objects,
2355+
// and extern types, the input safety requirement is currently enough to
2356+
// satisfy the requirements of for_value_raw; this is an implementation
2357+
// detail of the language that may not be relied upon outside of std.
2358+
let data_layout = Layout::for_value_raw(data_ptr);
2359+
RcStructAlloc::offset_of_data(data_layout) as isize
2360+
}
23572361
}

0 commit comments

Comments
 (0)