Skip to content

Commit e270d95

Browse files
committed
implement tri-color marking
1 parent 2fbadae commit e270d95

13 files changed

Lines changed: 267 additions & 195 deletions

File tree

oscars/src/alloc/mempool3/alloc.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,17 @@ impl<'pool> ErasedPoolPointer<'pool> {
6161
/// typed pointer into a pool slot
6262
#[derive(Debug, Clone, Copy)]
6363
#[repr(transparent)]
64-
pub struct PoolPointer<'pool, T>(NonNull<PoolItem<T>>, PhantomData<&'pool T>);
64+
pub struct PoolPointer<'pool, T>(NonNull<PoolItem<T>>, PhantomData<(&'pool (), *mut T)>);
6565

6666
impl<'pool, T> PoolPointer<'pool, T> {
6767
pub(crate) unsafe fn from_raw(raw: NonNull<PoolItem<T>>) -> Self {
6868
Self(raw, PhantomData)
6969
}
7070

71-
pub fn as_inner_ref(&self) -> &'pool T {
71+
pub fn as_inner_ref(&self) -> &'pool T
72+
where
73+
T: 'pool,
74+
{
7275
// SAFETY: pointer is valid and properly aligned
7376
unsafe { &(*self.0.as_ptr()).0 }
7477
}

oscars/src/collectors/mark_sweep_branded/cell.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Interior mutability for GC-managed values.
22
3-
use crate::collectors::mark_sweep_branded::trace::{Finalize, Trace, TraceColor};
3+
use crate::collectors::mark_sweep_branded::trace::{Finalize, Trace, Tracer};
44
use core::cell::{Ref, RefCell, RefMut};
55
use core::ops::{Deref, DerefMut};
66

@@ -65,7 +65,7 @@ impl<T: Trace> DerefMut for GcRefMut<'_, T> {
6565
impl<T: Trace> Finalize for GcRefCell<T> {}
6666

6767
impl<T: Trace> Trace for GcRefCell<T> {
68-
fn trace(&self, color: &TraceColor) {
69-
self.inner.borrow().trace(color);
68+
fn trace(&mut self, tracer: &mut Tracer) {
69+
self.inner.get_mut().trace(tracer);
7070
}
7171
}

oscars/src/collectors/mark_sweep_branded/ephemeron.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
gc::Gc,
55
gc_box::GcBox,
66
mutation_ctx::MutationContext,
7-
trace::{Finalize, Trace, TraceColor},
7+
trace::{Finalize, Trace, Tracer},
88
},
99
};
1010
use core::marker::PhantomData;
@@ -44,5 +44,5 @@ impl<'id, K: Trace, V: Trace> Copy for Ephemeron<'id, K, V> {}
4444
impl<'id, K: Trace, V: Trace> Finalize for Ephemeron<'id, K, V> {}
4545

4646
impl<'id, K: Trace, V: Trace> Trace for Ephemeron<'id, K, V> {
47-
fn trace(&self, _color: &TraceColor) {}
47+
fn trace(&mut self, _tracer: &mut Tracer) {}
4848
}

oscars/src/collectors/mark_sweep_branded/gc.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Core pointer types.
22
33
use crate::{
4-
alloc::mempool3::PoolItem,
4+
alloc::mempool3::{PoolAllocator, PoolItem},
55
collectors::mark_sweep_branded::{
66
gc_box::GcBox,
77
mutation_ctx::MutationContext,
@@ -13,7 +13,8 @@ use core::fmt;
1313
use core::marker::PhantomData;
1414
use core::ops::Deref;
1515
use core::ptr::NonNull;
16-
use rust_alloc::boxed::Box;
16+
17+
pub(crate) type RootDropFn = unsafe fn(&mut PoolAllocator<'static>, NonNull<u8>);
1718

1819
/// A transient pointer to a GC-managed value.
1920
#[derive(Debug)]
@@ -61,6 +62,10 @@ pub(crate) struct RootNode<'id, T: Trace> {
6162
pub(crate) link: RootLink,
6263
/// Pointer to the allocation
6364
pub(crate) gc_ptr: NonNull<PoolItem<GcBox<T>>>,
65+
/// Type-erased drop function for freeing this RootNode
66+
pub(crate) drop_fn: RootDropFn,
67+
/// Raw pointer to the Collector for freeing this node
68+
pub(crate) collector_ptr: *const crate::collectors::mark_sweep_branded::Collector,
6469
pub(crate) _marker: PhantomData<*mut &'id ()>,
6570
}
6671

@@ -83,21 +88,21 @@ impl<'id, T: Trace> Root<'id, T> {
8388

8489
impl<'id, T: Trace> Drop for Root<'id, T> {
8590
fn drop(&mut self) {
86-
// SAFETY:
87-
// * `self.raw` was created by `Box::into_raw`
88-
// * The address is stable.
8991
unsafe {
90-
let node = Box::from_raw(self.raw.as_ptr());
91-
if node.link.is_linked() {
92-
RootLink::unlink(NonNull::from(&node.link));
92+
let node_ref = self.raw.as_ref();
93+
if node_ref.link.is_linked() {
94+
RootLink::unlink(NonNull::from(&node_ref.link));
9395
}
96+
// SAFETY: collector_ptr is valid for the lifetime of the GcContext
97+
let collector = &*node_ref.collector_ptr;
98+
collector.free_root_node(self.raw.cast::<u8>(), node_ref.drop_fn);
9499
}
95100
}
96101
}
97102

98103
impl<T: Trace> Finalize for Gc<'_, T> {}
99104
impl<T: Trace> Trace for Gc<'_, T> {
100-
fn trace(&self, color: &crate::collectors::mark_sweep_branded::trace::TraceColor) {
101-
color.mark(self);
105+
fn trace(&mut self, tracer: &mut crate::collectors::mark_sweep_branded::trace::Tracer) {
106+
tracer.mark(self);
102107
}
103108
}

oscars/src/collectors/mark_sweep_branded/gc_box.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,29 @@
33
use core::cell::Cell;
44
use core::ptr::NonNull;
55

6-
use crate::alloc::mempool3::PoolAllocator;
7-
use crate::collectors::mark_sweep_branded::trace::TraceFn;
6+
use crate::alloc::mempool3::{PoolAllocator, PoolItem};
7+
use crate::collectors::mark_sweep_branded::trace::{Trace, TraceFn, Tracer};
88

99
pub(crate) type DropFn = unsafe fn(&mut PoolAllocator<'static>, NonNull<u8>);
1010

11+
/// The tri-color marking state of a [`GcBox`]
12+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13+
#[repr(u8)]
14+
pub(crate) enum GcColor {
15+
/// Not yet reached by mark phase
16+
White = 0,
17+
/// Reached and queued in the worklist, children not yet traced.
18+
Gray = 1,
19+
/// Reached and dequeued from the worklist, all children traced
20+
Black = 2,
21+
}
22+
1123
/// Heap wrapper for a garbage-collected value.
1224
///
1325
/// Allocated via [`PoolAllocator`].
1426
pub(crate) struct GcBox<T: ?Sized> {
15-
/// Reachability flag set by the mark phase.
16-
pub(crate) marked: Cell<bool>,
27+
/// tricolor marking state, updated by the mark phase
28+
pub(crate) color: Cell<GcColor>,
1729
/// Type-erased trace function.
1830
pub(crate) trace_fn: TraceFn,
1931
/// Type-erased finalize and free fn
@@ -27,3 +39,29 @@ pub(crate) struct GcBox<T: ?Sized> {
2739
impl<T: ?Sized> GcBox<T> {
2840
pub(crate) const FREED_ALLOC_ID: usize = usize::MAX;
2941
}
42+
43+
impl<T> GcBox<T> {
44+
/// Create a [`GcBox`] for `value`, `color` starts as [`GcColor::White`]
45+
pub(crate) fn new(value: T, trace_fn: TraceFn, drop_fn: DropFn, alloc_id: usize) -> Self {
46+
Self {
47+
color: Cell::new(GcColor::White),
48+
trace_fn,
49+
drop_fn,
50+
alloc_id,
51+
value,
52+
}
53+
}
54+
}
55+
56+
/// type-erased trace function for a `GcBox<T>` slot.
57+
///
58+
/// # Safety
59+
///
60+
/// `ptr` must point to a live `PoolItem<GcBox<T>>` in the pool allocator
61+
pub(crate) unsafe fn trace_value<T: Trace>(ptr: NonNull<u8>, tracer: &mut Tracer<'_>) {
62+
let pool_item_ptr = ptr.cast::<PoolItem<GcBox<T>>>();
63+
unsafe {
64+
(*pool_item_ptr.as_ptr()).0.color.set(GcColor::Black);
65+
(*pool_item_ptr.as_ptr()).0.value.trace(tracer);
66+
}
67+
}

0 commit comments

Comments
 (0)