Skip to content

Commit 8293713

Browse files
committed
Restructure Rc and Arc metadata for uniform access via a PrefixAlloc
1 parent 3070db1 commit 8293713

File tree

5 files changed

+145
-110
lines changed

5 files changed

+145
-110
lines changed

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#![cfg_attr(test, feature(test))]
7777
#![cfg_attr(test, feature(new_uninit))]
7878
#![feature(allocator_api)]
79+
#![feature(allocator_api_internals)]
7980
#![feature(vec_extend_from_within)]
8081
#![feature(array_chunks)]
8182
#![feature(array_methods)]

library/alloc/src/rc.rs

+64-41
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ use crate::boxed::Box;
247247
#[cfg(test)]
248248
use std::boxed::Box;
249249

250+
use core::alloc::helper::PrefixAllocator;
250251
use core::any::Any;
251252
use core::borrow;
252253
use core::cell::Cell;
@@ -257,7 +258,7 @@ use core::hash::{Hash, Hasher};
257258
use core::intrinsics::abort;
258259
use core::iter;
259260
use core::marker::{self, PhantomData, Unpin, Unsize};
260-
use core::mem::{self, align_of_val_raw, forget, size_of_val};
261+
use core::mem::{self, forget, size_of_val, MaybeUninit};
261262
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
262263
use core::pin::Pin;
263264
use core::ptr::{self, NonNull};
@@ -273,13 +274,33 @@ use crate::vec::Vec;
273274
#[cfg(test)]
274275
mod tests;
275276

277+
struct RcBoxMetadata {
278+
strong: Cell<usize>,
279+
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+
276298
// This is repr(C) to future-proof against possible field-reordering, which
277299
// would interfere with otherwise safe [into|from]_raw() of transmutable
278300
// inner types.
279301
#[repr(C)]
280302
struct RcBox<T: ?Sized> {
281-
strong: Cell<usize>,
282-
weak: Cell<usize>,
303+
meta: RcBoxMetadata,
283304
value: T,
284305
}
285306

@@ -319,10 +340,12 @@ impl<T: ?Sized> Rc<T> {
319340
unsafe { self.ptr.as_ref() }
320341
}
321342

343+
#[inline]
322344
fn from_inner(ptr: NonNull<RcBox<T>>) -> Self {
323345
Self { ptr, phantom: PhantomData }
324346
}
325347

348+
#[inline]
326349
unsafe fn from_ptr(ptr: *mut RcBox<T>) -> Self {
327350
Self::from_inner(unsafe { NonNull::new_unchecked(ptr) })
328351
}
@@ -340,13 +363,7 @@ impl<T> Rc<T> {
340363
/// ```
341364
#[stable(feature = "rust1", since = "1.0.0")]
342365
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-
)
366+
Self::from_inner(Box::leak(box RcBox { meta: RcBoxMetadata::new_strong(), value }).into())
350367
}
351368

352369
/// Constructs a new `Rc<T>` using a weak reference to itself. Attempting
@@ -378,8 +395,7 @@ impl<T> Rc<T> {
378395
// Construct the inner in the "uninitialized" state with a single
379396
// weak reference.
380397
let uninit_ptr: NonNull<_> = Box::leak(box RcBox {
381-
strong: Cell::new(0),
382-
weak: Cell::new(1),
398+
meta: RcBoxMetadata::new_weak(),
383399
value: mem::MaybeUninit::<T>::uninit(),
384400
})
385401
.into();
@@ -400,9 +416,9 @@ impl<T> Rc<T> {
400416
let inner = init_ptr.as_ptr();
401417
ptr::write(ptr::addr_of_mut!((*inner).value), data);
402418

403-
let prev_value = (*inner).strong.get();
419+
let prev_value = (*inner).meta.strong.get();
404420
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
405-
(*inner).strong.set(1);
421+
(*inner).meta.strong.set(1);
406422
}
407423

408424
let strong = Rc::from_inner(init_ptr);
@@ -494,8 +510,7 @@ impl<T> Rc<T> {
494510
// the allocation while the strong destructor is running, even
495511
// if the weak pointer is stored inside the strong one.
496512
Ok(Self::from_inner(
497-
Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?)
498-
.into(),
513+
Box::leak(Box::try_new(RcBox { meta: RcBoxMetadata::new_strong(), value })?).into(),
499514
))
500515
}
501516

@@ -846,13 +861,7 @@ impl<T: ?Sized> Rc<T> {
846861
/// ```
847862
#[stable(feature = "rc_raw", since = "1.17.0")]
848863
pub unsafe fn from_raw(ptr: *const T) -> Self {
849-
let offset = unsafe { data_offset(ptr) };
850-
851-
// Reverse the offset to find the original RcBox.
852-
let rc_ptr =
853-
unsafe { (ptr as *mut RcBox<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) };
854-
855-
unsafe { Self::from_ptr(rc_ptr) }
864+
unsafe { Self::from_data_ptr(ptr).assume_init() }
856865
}
857866

858867
/// Creates a new [`Weak`] pointer to this allocation.
@@ -1237,8 +1246,8 @@ impl<T: ?Sized> Rc<T> {
12371246
unsafe {
12381247
debug_assert_eq!(Layout::for_value(&*inner), layout);
12391248

1240-
ptr::write(&mut (*inner).strong, Cell::new(1));
1241-
ptr::write(&mut (*inner).weak, Cell::new(1));
1249+
ptr::write(&mut (*inner).meta.strong, Cell::new(1));
1250+
ptr::write(&mut (*inner).meta.weak, Cell::new(1));
12421251
}
12431252

12441253
Ok(inner)
@@ -1277,6 +1286,23 @@ impl<T: ?Sized> Rc<T> {
12771286
Self::from_ptr(ptr)
12781287
}
12791288
}
1289+
1290+
/// # Safety
1291+
///
1292+
/// The caller must ensure that the pointer points to the `value` field of a `Global`
1293+
/// allocation of type `RcBox<T>`. Depending on how the pointer was created, the
1294+
/// `meta` field might or might not be uninitialized. It's up to the caller to ensure
1295+
/// that this field is set to the correct value before the return value is unwrapped.
1296+
#[inline]
1297+
unsafe fn from_data_ptr(ptr: *const T) -> MaybeUninit<Self> {
1298+
let offset = unsafe { data_offset(ptr) };
1299+
1300+
// Reverse the offset to find the original RcBox.
1301+
let rc_ptr =
1302+
unsafe { (ptr as *mut RcBox<T>).set_ptr_value((ptr as *mut u8).offset(-offset)) };
1303+
1304+
unsafe { MaybeUninit::new(Self::from_ptr(rc_ptr)) }
1305+
}
12801306
}
12811307

12821308
impl<T> Rc<[T]> {
@@ -2206,7 +2232,7 @@ impl<T: ?Sized> Weak<T> {
22062232
// is dropped, the data field will be dropped in-place).
22072233
Some(unsafe {
22082234
let ptr = self.ptr.as_ptr();
2209-
WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak }
2235+
WeakInner { strong: &(*ptr).meta.strong, weak: &(*ptr).meta.weak }
22102236
})
22112237
}
22122238
}
@@ -2415,12 +2441,12 @@ trait RcInnerPtr {
24152441
impl<T: ?Sized> RcInnerPtr for RcBox<T> {
24162442
#[inline(always)]
24172443
fn weak_ref(&self) -> &Cell<usize> {
2418-
&self.weak
2444+
&self.meta.weak
24192445
}
24202446

24212447
#[inline(always)]
24222448
fn strong_ref(&self) -> &Cell<usize> {
2423-
&self.strong
2449+
&self.meta.strong
24242450
}
24252451
}
24262452

@@ -2453,24 +2479,21 @@ impl<T: ?Sized> AsRef<T> for Rc<T> {
24532479
#[stable(feature = "pin", since = "1.33.0")]
24542480
impl<T: ?Sized> Unpin for Rc<T> {}
24552481

2482+
type RcAllocator = PrefixAllocator<RcBoxMetadata, Global>;
2483+
24562484
/// Get the offset within an `RcBox` for the payload behind a pointer.
24572485
///
24582486
/// # Safety
24592487
///
24602488
/// The pointer must point to (and have valid metadata for) a previously
24612489
/// valid instance of T, but the T is allowed to be dropped.
24622490
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
2463-
// Align the unsized value to the end of the RcBox.
2464-
// Because RcBox is repr(C), it will always be the last field in memory.
2465-
// SAFETY: since the only unsized types possible are slices, trait objects,
2466-
// and extern types, the input safety requirement is currently enough to
2467-
// satisfy the requirements of align_of_val_raw; this is an implementation
2468-
// detail of the language that may not be relied upon outside of std.
2469-
unsafe { data_offset_align(align_of_val_raw(ptr)) }
2470-
}
2471-
2472-
#[inline]
2473-
fn data_offset_align(align: usize) -> isize {
2474-
let layout = Layout::new::<RcBox<()>>();
2475-
(layout.size() + layout.padding_needed_for(align)) as isize
2491+
unsafe {
2492+
// SAFETY: since the only unsized types possible are slices, trait objects,
2493+
// and extern types, the input safety requirement is currently enough to
2494+
// satisfy the requirements of for_value_raw; this is an implementation
2495+
// detail of the language that may not be relied upon outside of std.
2496+
let layout = Layout::for_value_raw(ptr);
2497+
RcAllocator::prefix_offset(layout) as isize
2498+
}
24762499
}

0 commit comments

Comments
 (0)