Skip to content

Commit 44dc03b

Browse files
committed
refactor: move RootNode, Root and RootLink into separate root module
1 parent a98ad8e commit 44dc03b

9 files changed

Lines changed: 228 additions & 111 deletions

File tree

oscars/src/collectors/mark_sweep_branded/gc.rs

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
11
//! Core pointer types.
22
33
use crate::{
4-
alloc::mempool3::{PoolAllocator, PoolPointer},
4+
alloc::mempool3::PoolPointer,
55
collectors::mark_sweep_branded::{
66
gc_box::GcBox,
7-
mutation_ctx::MutationContext,
8-
root_link::RootLink,
97
trace::{Finalize, Trace},
108
},
119
};
1210
use core::fmt;
1311
use core::marker::PhantomData;
1412
use core::ops::Deref;
15-
use core::ptr::NonNull;
16-
17-
pub(crate) type RootDropFn = unsafe fn(&mut PoolAllocator<'static>, NonNull<u8>);
1813

1914
/// A transient pointer to a GC-managed value.
2015
#[derive(Debug)]
@@ -55,62 +50,6 @@ impl<'gc, T: Trace + 'gc> Deref for Gc<'gc, T> {
5550
}
5651
}
5752

58-
/// Heap node backing a `Root`.
59-
#[repr(C)]
60-
pub(crate) struct RootNode<'id, T: Trace> {
61-
/// Intrusive list link
62-
pub(crate) link: RootLink,
63-
/// Pointer to the allocation
64-
pub(crate) gc_ptr: PoolPointer<'static, 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,
69-
pub(crate) _marker: PhantomData<*mut &'id ()>,
70-
}
71-
72-
/// Type-erased version of [`RootNode`] for use during collection.
73-
///
74-
/// Since [`RootNode`] is `repr(C)` and `link` is always the first field,
75-
/// a `NonNull<RootLink>` from the sentinel iterator can be safely cast to
76-
/// `NonNull<ErasedRootNode>` to read `gc_ptr` without knowing `T`.
77-
#[repr(C)]
78-
pub(crate) struct ErasedRootNode {
79-
pub(crate) link: RootLink,
80-
pub(crate) gc_ptr: PoolPointer<'static, GcBox<()>>,
81-
}
82-
83-
/// A handle that keeps a GC allocation live.
84-
#[must_use = "dropping a root unregisters it from the GC"]
85-
pub struct Root<'id, T: Trace> {
86-
pub(crate) raw: NonNull<RootNode<'id, T>>,
87-
}
88-
89-
impl<'id, T: Trace> Root<'id, T> {
90-
/// Converts this root into a `Gc` pointer
91-
pub fn get<'gc>(&self, _cx: &MutationContext<'id, 'gc>) -> Gc<'gc, T> {
92-
Gc {
93-
// SAFETY: `raw` is non-null and valid.
94-
ptr: unsafe { self.raw.as_ref().gc_ptr },
95-
_marker: PhantomData,
96-
}
97-
}
98-
}
99-
100-
impl<'id, T: Trace> Drop for Root<'id, T> {
101-
fn drop(&mut self) {
102-
unsafe {
103-
let node_ref = self.raw.as_ref();
104-
if node_ref.link.is_linked() {
105-
RootLink::unlink(NonNull::from(&node_ref.link));
106-
}
107-
// SAFETY: collector_ptr is valid for the lifetime of the GcContext
108-
let collector = &*node_ref.collector_ptr;
109-
collector.free_root_node(self.raw.cast::<u8>(), node_ref.drop_fn);
110-
}
111-
}
112-
}
113-
11453
impl<T: Trace> Finalize for Gc<'_, T> {}
11554
impl<T: Trace> Trace for Gc<'_, T> {
11655
fn trace(&mut self, tracer: &mut crate::collectors::mark_sweep_branded::trace::Tracer) {

oscars/src/collectors/mark_sweep_branded/mod.rs

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub mod ephemeron;
66
pub mod gc;
77
pub mod gc_box;
88
pub mod mutation_ctx;
9-
pub mod root_link;
9+
pub mod root;
1010
pub mod trace;
1111
pub mod weak;
1212

@@ -15,8 +15,9 @@ mod tests;
1515

1616
pub use cell::GcRefCell;
1717
pub use ephemeron::Ephemeron;
18-
pub use gc::{Gc, Root};
18+
pub use gc::Gc;
1919
pub use mutation_ctx::MutationContext;
20+
pub use root::Root;
2021
pub use trace::{Finalize, Trace, Tracer};
2122
pub use weak::WeakGc;
2223

@@ -25,7 +26,7 @@ use core::cell::{Cell, RefCell};
2526
use core::marker::PhantomData;
2627
use core::ptr::NonNull;
2728
use gc_box::{DropFn, GcBox, GcColor};
28-
use root_link::RootSentinel;
29+
use root::RootSentinel;
2930
use rust_alloc::vec::Vec;
3031

3132
/// Type-erased ephemeron registration.
@@ -70,39 +71,18 @@ impl Collector {
7071
}
7172

7273
/// Allocates a RootNode from the dedicated root pool.
73-
pub(crate) fn alloc_root_node<'id, T: trace::Trace>(
74+
pub(crate) fn try_alloc_root_node<'id, T: trace::Trace>(
7475
&self,
7576
gc_ptr: PoolPointer<'static, GcBox<T>>,
76-
) -> NonNull<gc::RootNode<'id, T>> {
77-
unsafe fn drop_and_free<T: trace::Trace>(
78-
pool: &mut PoolAllocator<'static>,
79-
ptr: NonNull<u8>,
80-
) {
81-
use crate::alloc::mempool3::PoolItem;
82-
unsafe {
83-
let typed_ptr = ptr.cast::<PoolItem<gc::RootNode<'_, T>>>();
84-
core::ptr::drop_in_place(typed_ptr.as_ptr());
85-
pool.free_slot(ptr);
86-
}
87-
}
88-
77+
) -> Result<NonNull<root::RootNode<'id, T>>, PoolAllocError> {
8978
let mut pool = self.root_pool.borrow_mut();
90-
let ptr = pool
91-
.try_alloc(gc::RootNode {
92-
link: root_link::RootLink::new(),
93-
gc_ptr,
94-
drop_fn: drop_and_free::<T>,
95-
collector_ptr: self as *const Collector,
96-
_marker: PhantomData,
97-
})
98-
.expect("root pool allocation failed");
99-
79+
let ptr = pool.try_alloc(root::RootNode::new_in(gc_ptr, self))?;
10080
// SAFETY: PoolItem<T> is repr(transparent) over T; pointer address is identical.
101-
ptr.as_ptr().cast::<gc::RootNode<'id, T>>()
81+
Ok(ptr.as_ptr().cast::<root::RootNode<'id, T>>())
10282
}
10383

10484
/// Frees a RootNode back to the root pool.
105-
pub(crate) fn free_root_node(&self, ptr: NonNull<u8>, drop_fn: gc::RootDropFn) {
85+
pub(crate) fn free_root_node(&self, ptr: NonNull<u8>, drop_fn: root::RootDropFn) {
10686
let mut pool = self.root_pool.borrow_mut();
10787
unsafe {
10888
(drop_fn)(&mut pool, ptr);
@@ -172,7 +152,7 @@ impl Collector {
172152
// SAFETY: link_ptr points to the `link` field which is first in repr(C) RootNode.
173153
// Casting to ErasedRootNode (also repr(C), same first two fields) lets us read
174154
// gc_ptr without knowing T, avoiding manual offset arithmetic.
175-
let erased = link_ptr.cast::<gc::ErasedRootNode>();
155+
let erased = link_ptr.cast::<root::ErasedRootNode>();
176156
tracer.mark_raw((*erased.as_ptr()).gc_ptr.as_ptr().cast::<u8>());
177157
}
178158
}
@@ -244,12 +224,12 @@ impl Drop for Collector {
244224
use crate::alloc::mempool3::PoolItem;
245225

246226
// Free all root nodes first
247-
let all_roots: Vec<(NonNull<u8>, gc::RootDropFn)> = self
227+
let all_roots: Vec<(NonNull<u8>, root::RootDropFn)> = self
248228
.root_pool
249229
.borrow()
250230
.iter_live_slots()
251231
.map(|ptr| unsafe {
252-
let drop_fn = (*ptr.cast::<PoolItem<gc::RootNode<'_, ()>>>().as_ptr())
232+
let drop_fn = (*ptr.cast::<PoolItem<root::RootNode<'_, ()>>>().as_ptr())
253233
.0
254234
.drop_fn;
255235
(ptr, drop_fn)

oscars/src/collectors/mark_sweep_branded/mutation_ctx.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use crate::{
55
collectors::mark_sweep_branded::{
66
Collector,
77
ephemeron::Ephemeron,
8-
gc::{Gc, Root},
8+
gc::Gc,
99
gc_box::GcBox,
10-
root_link::RootLink,
10+
root::{Root, RootLink},
1111
trace::{Finalize, Trace},
1212
weak::WeakGc,
1313
},
@@ -37,8 +37,11 @@ impl<'id, 'gc> MutationContext<'id, 'gc> {
3737
}
3838

3939
/// Promotes a `Gc` pointer to a `Root`
40-
pub fn root<T: Trace + Finalize + 'gc>(&self, gc: Gc<'gc, T>) -> Root<'id, T> {
41-
let raw = self.collector.alloc_root_node(gc.ptr);
40+
pub fn root<T: Trace + Finalize + 'gc>(
41+
&self,
42+
gc: Gc<'gc, T>,
43+
) -> Result<Root<'id, T>, PoolAllocError> {
44+
let raw = self.collector.try_alloc_root_node(gc.ptr)?;
4245

4346
// SAFETY: `raw` points to a stable `RootNode`.
4447
unsafe {
@@ -47,7 +50,7 @@ impl<'id, 'gc> MutationContext<'id, 'gc> {
4750
RootLink::link_after(sentinel_ptr, link_ptr);
4851
}
4952

50-
Root { raw }
53+
Ok(Root { raw })
5154
}
5255

5356
/// Creates an ephemeron binding `key` to `value`.

0 commit comments

Comments
 (0)