2022-05-16 15:11:41 +02:00
|
|
|
use std::ptr::NonNull;
|
|
|
|
|
|
|
|
use super::gc_ref::GcRef;
|
|
|
|
use super::trace;
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct GCAllocator {
|
|
|
|
allocations: Vec<Allocation>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GCAllocator {
|
|
|
|
#[inline(always)]
|
2022-07-09 22:07:23 +02:00
|
|
|
pub fn alloc<T: trace::GCTrace>(&mut self, x: T) -> GcRef<T> {
|
2022-05-16 15:11:41 +02:00
|
|
|
let alloc = Allocation::new(x);
|
|
|
|
let ptr = alloc.ptr as *mut T;
|
|
|
|
self.allocations.push(alloc);
|
|
|
|
unsafe { GcRef::new(NonNull::new(ptr).unwrap()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// # Safety
|
|
|
|
/// Root needs to contain all the accessible gc allocated references
|
|
|
|
/// In case root itself is gc allocated use [`gc_ref_root`]
|
|
|
|
///
|
|
|
|
/// [`gc_ref_root`]: GCAllocator::gc_ref_root
|
|
|
|
pub unsafe fn gc<T: trace::GCTrace>(&mut self, root: &T) {
|
|
|
|
// Mark
|
|
|
|
let mut tracer = trace::GCTracer::with_capacity(self.allocations.len());
|
|
|
|
root.trace(&mut tracer);
|
|
|
|
|
|
|
|
// And sweep
|
|
|
|
self.allocations
|
|
|
|
.drain_filter(|a| !tracer.is_accessible(a.ptr));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Specialization when ;-;
|
|
|
|
/// [`gc`] but for roots that are allocated on the heap
|
|
|
|
/// # Safety
|
|
|
|
/// See [`gc`]
|
|
|
|
///
|
|
|
|
/// [`gc`]: GCAllocator::gc
|
|
|
|
pub unsafe fn gc_ref_root<T: trace::GCTrace>(&mut self, root: &GcRef<T>) {
|
|
|
|
// Mark
|
|
|
|
let mut tracer = trace::GCTracer::with_capacity(self.allocations.len());
|
2022-07-09 22:07:23 +02:00
|
|
|
tracer.mark_reachable_rec(root);
|
2022-05-16 15:11:41 +02:00
|
|
|
root.trace(&mut tracer);
|
|
|
|
|
|
|
|
// And sweep
|
|
|
|
self.allocations
|
|
|
|
.drain_filter(|a| !tracer.is_accessible(a.ptr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Allocation {
|
|
|
|
ptr: *mut (),
|
|
|
|
drop: unsafe fn(*mut ()),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Allocation {
|
|
|
|
fn new<T>(x: T) -> Self {
|
|
|
|
let alloc = Box::new(x);
|
|
|
|
let ptr = Box::into_raw(alloc) as *mut ();
|
|
|
|
|
|
|
|
let drop = |ptr| unsafe {
|
|
|
|
Box::from_raw(ptr as *mut T);
|
|
|
|
};
|
|
|
|
|
|
|
|
Self { ptr, drop }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Allocation {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe { (self.drop)(self.ptr) };
|
|
|
|
}
|
|
|
|
}
|