crftng-intrprtrs/gc/src/allocator.rs

87 lines
1.9 KiB
Rust
Raw Normal View History

2022-05-16 15:11:41 +02:00
use std::ptr::NonNull;
use super::gc_ref::GcRef;
use super::trace;
use crate::trace::GCTrace;
2022-05-16 15:11:41 +02:00
#[derive(Default)]
pub struct GCAllocator {
allocations: Vec<Allocation>,
}
impl GCAllocator {
#[inline(always)]
/// Allocate a value on the heap
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
let inaccessible = self
.allocations
2022-05-16 15:11:41 +02:00
.drain_filter(|a| !tracer.is_accessible(a.ptr));
// And sweep
for mut to_free in inaccessible {
to_free.drop();
}
2022-05-16 15:11:41 +02:00
}
// 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);
let inaccessible = self
.allocations
2022-05-16 15:11:41 +02:00
.drain_filter(|a| !tracer.is_accessible(a.ptr));
// And sweep
for mut to_free in inaccessible {
to_free.drop();
}
2022-05-16 15:11:41 +02:00
}
}
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 {
std::mem::drop(Box::from_raw(ptr as *mut T));
2022-05-16 15:11:41 +02:00
};
Self { ptr, drop }
}
fn drop(&mut self) {
unsafe { (self.drop)(self.ptr) };
}
}