Skip to content

Commit e34dabd

Browse files
committed
reduce dupliaction between mark_sweep and mark_sweep_arena2
1 parent 794371d commit e34dabd

File tree

17 files changed

+96
-1369
lines changed

17 files changed

+96
-1369
lines changed

oscars/src/alloc/arena2/alloc.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,17 @@ impl<T: ?Sized> ArenaHeapItem<T> {
4444
&mut self.value as *mut T
4545
}
4646

47-
pub(crate) fn value_mut(&mut self) -> &mut T {
47+
/// Returns a raw mutable pointer to the value
48+
///
49+
/// This avoids creating a `&mut self` reference, which can lead to stacked borrows
50+
/// if shared references to the heap item exist
51+
pub(crate) fn as_value_ptr(ptr: NonNull<Self>) -> *mut T {
52+
// SAFETY: `&raw mut` computes the field address without creating a
53+
// reference
54+
unsafe { &raw mut (*ptr.as_ptr()).value }
55+
}
56+
57+
fn value_mut(&mut self) -> &mut T {
4858
&mut self.value
4959
}
5060
}
@@ -133,6 +143,15 @@ impl<'arena> ErasedArenaPointer<'arena> {
133143
self.0.as_ptr()
134144
}
135145

146+
/// Extend the lifetime of this erased arena pointer to 'static
147+
///
148+
/// SAFETY:
149+
///
150+
/// safe because the gc collector owns the arena and keeps it alive
151+
pub(crate) unsafe fn extend_lifetime(self) -> ErasedArenaPointer<'static> {
152+
ErasedArenaPointer(self.0, PhantomData)
153+
}
154+
136155
/// Returns an [`ArenaPointer`] for the current [`ErasedArenaPointer`]
137156
///
138157
/// # Safety
@@ -178,6 +197,15 @@ impl<'arena, T> ArenaPointer<'arena, T> {
178197
pub fn to_erased(self) -> ErasedArenaPointer<'arena> {
179198
self.0
180199
}
200+
201+
/// extend the lifetime of this arena pointer to 'static
202+
///
203+
/// SAFETY:
204+
///
205+
/// safe because the gc collector owns the arena and keeps it alive
206+
pub(crate) unsafe fn extend_lifetime(self) -> ArenaPointer<'static, T> {
207+
ArenaPointer(unsafe { self.0.extend_lifetime() }, PhantomData)
208+
}
181209
}
182210

183211
const FULL_MASK: u8 = 0b0100_0000;

oscars/src/alloc/arena2/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fn arc_drop() {
7777
let heap_item_mut = heap_item.as_mut();
7878
// Manually drop the heap item
7979
heap_item_mut.mark_dropped();
80-
drop_in_place(heap_item_mut.value_mut());
80+
drop_in_place(ArenaHeapItem::as_value_ptr(heap_item));
8181
};
8282

8383
assert!(dropped.load(Ordering::SeqCst));

oscars/src/collectors/mark_sweep/cell.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ impl<T: ?Sized> GcRefCell<T> {
171171
}
172172
}
173173

174+
// returns a raw pointer to the inner value or `None` if currently mutably borrowed
175+
pub(crate) fn get_raw(&self) -> Option<*mut T> {
176+
match self.borrow.get().borrowed() {
177+
BorrowState::Writing => None,
178+
_ => Some(self.cell.get()),
179+
}
180+
}
181+
174182
/// Mutably borrows the wrapped value, returning an error if the value is currently borrowed.
175183
///
176184
/// The borrow lasts until the returned `GcCellRefMut` exits scope.

oscars/src/collectors/mark_sweep/internals/gc_box.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ impl<T: Trace + Finalize + ?Sized> WeakGcBox<T> {
4646
pub(crate) fn erased_inner_ptr(&self) -> NonNull<GcBox<NonTraceable>> {
4747
// SAFETY: `as_heap_ptr` returns a valid pointer to
4848
// `PoolItem` whose lifetime is tied to the pool
49-
let heap_item = unsafe { self.as_heap_ptr().as_mut() };
50-
// SAFETY: We just removed this value from a NonNull
51-
unsafe { NonNull::new_unchecked(heap_item.as_ptr()) }
49+
let heap_item: *mut PoolItem<GcBox<NonTraceable>> = self.as_heap_ptr().as_ptr();
50+
// SAFETY: `PoolItem` is repr(transparent), so pointing to and returning field 0 is valid.
51+
unsafe { NonNull::new_unchecked(&raw mut (*heap_item).0) }
5252
}
5353

5454
pub(crate) fn as_heap_ptr(&self) -> NonNull<PoolItem<GcBox<NonTraceable>>> {

oscars/src/collectors/mark_sweep/internals/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod gc_header;
44
mod vtable;
55

66
pub(crate) use ephemeron::Ephemeron;
7+
pub(crate) use gc_header::{GcHeader, HeaderColor};
78
pub(crate) use vtable::{DropFn, TraceFn, VTable, vtable_of};
89

910
pub use self::gc_box::{GcBox, NonTraceable, WeakGcBox};

oscars/src/collectors/mark_sweep/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ impl MarkSweepGarbageCollector {
171171

172172
// Force drops all elements in the internal tracking queues and clears
173173
// them without regard for reachability.
174+
//
175+
// NOTE: This intentionally differs from arena2's sweep_all_queues.
176+
// arena3 uses`free_slot` calls to reclaim memory.
177+
// arena2 uses a bitmap (`mark_dropped`) and reclaims automatically
174178
fn sweep_all_queues(&self) {
175179
let ephemerons = core::mem::take(&mut *self.ephemeron_queue.borrow_mut());
176180
for ephemeron in ephemerons {

oscars/src/collectors/mark_sweep/pointers/gc.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ impl<T: Trace> Gc<T> {
4444

4545
impl<T: Trace + ?Sized> Gc<T> {
4646
pub(crate) fn as_sized_inner_ptr(&self) -> NonNull<GcBox<NonTraceable>> {
47-
// SAFETY: use `addr_of_mut!` to get a raw pointer without creating
47+
// SAFETY: use `&raw mut` to get a raw pointer without creating
4848
// a `&mut` reference, avoiding Stacked Borrows UB during GC tracing
49-
let raw: *mut ArenaHeapItem<GcBox<NonTraceable>> = self.as_heap_ptr().as_ptr();
49+
let raw: *mut PoolItem<GcBox<NonTraceable>> = self.as_heap_ptr().as_ptr();
5050
// SAFETY: `raw` is non-null because it comes from `as_heap_ptr()`
51-
// `ArenaHeapItem` is `#[repr(transparent)]` so it shares the same address as field 0
52-
unsafe { NonNull::new_unchecked(core::ptr::addr_of_mut!((*raw).0)) }
51+
// `PoolItem` is `#[repr(transparent)]` so it shares the same address as field 0
52+
unsafe { NonNull::new_unchecked(&raw mut (*raw).0) }
5353
}
5454

5555
pub(crate) fn as_heap_ptr(&self) -> NonNull<PoolItem<GcBox<NonTraceable>>> {

0 commit comments

Comments
 (0)