Compare commits

..

No commits in common. "8c95fcbd85e9971065a5e31af4885df21835db45" and "cd1d83714bc7cf148fe144d64df1259d33bff386" have entirely different histories.

5 changed files with 27 additions and 53 deletions

View file

@ -2,7 +2,6 @@ use std::ptr::NonNull;
use super::gc_ref::GcRef; use super::gc_ref::GcRef;
use super::trace; use super::trace;
use crate::trace::GCTrace;
#[derive(Default)] #[derive(Default)]
pub struct GCAllocator { pub struct GCAllocator {
@ -11,7 +10,6 @@ pub struct GCAllocator {
impl GCAllocator { impl GCAllocator {
#[inline(always)] #[inline(always)]
/// Allocate a value on the heap
pub fn alloc<T: trace::GCTrace>(&mut self, x: T) -> GcRef<T> { pub fn alloc<T: trace::GCTrace>(&mut self, x: T) -> GcRef<T> {
let alloc = Allocation::new(x); let alloc = Allocation::new(x);
let ptr = alloc.ptr as *mut T; let ptr = alloc.ptr as *mut T;
@ -30,14 +28,8 @@ impl GCAllocator {
root.trace(&mut tracer); root.trace(&mut tracer);
// And sweep // And sweep
let inaccessible = self self.allocations
.allocations
.drain_filter(|a| !tracer.is_accessible(a.ptr)); .drain_filter(|a| !tracer.is_accessible(a.ptr));
// And sweep
for mut to_free in inaccessible {
to_free.drop();
}
} }
// Specialization when ;-; // Specialization when ;-;
@ -52,14 +44,9 @@ impl GCAllocator {
tracer.mark_reachable_rec(root); tracer.mark_reachable_rec(root);
root.trace(&mut tracer); root.trace(&mut tracer);
let inaccessible = self
.allocations
.drain_filter(|a| !tracer.is_accessible(a.ptr));
// And sweep // And sweep
for mut to_free in inaccessible { self.allocations
to_free.drop(); .drain_filter(|a| !tracer.is_accessible(a.ptr));
}
} }
} }
@ -74,12 +61,14 @@ impl Allocation {
let ptr = Box::into_raw(alloc) as *mut (); let ptr = Box::into_raw(alloc) as *mut ();
let drop = |ptr| unsafe { let drop = |ptr| unsafe {
std::mem::drop(Box::from_raw(ptr as *mut T)); Box::from_raw(ptr as *mut T);
}; };
Self { ptr, drop } Self { ptr, drop }
} }
}
impl Drop for Allocation {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { (self.drop)(self.ptr) }; unsafe { (self.drop)(self.ptr) };
} }

View file

@ -1,4 +1,4 @@
use std::{marker::PhantomData, ptr::NonNull}; use std::{marker::PhantomData, ops::Deref, ptr::NonNull};
use crate::trace::GCTrace; use crate::trace::GCTrace;
@ -10,34 +10,23 @@ impl<T: GCTrace> Clone for GcRef<T> {
} }
} }
impl<T: GCTrace> Deref for GcRef<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl<T: GCTrace> GcRef<T> { impl<T: GCTrace> GcRef<T> {
pub(crate) unsafe fn new(ptr: NonNull<T>) -> Self { pub(crate) unsafe fn new(ptr: NonNull<T>) -> Self {
Self(ptr, PhantomData) Self(ptr, PhantomData)
} }
/// # Safety /// # Safety
/// The caller needs to ensure that the underlying pointer hasn't been garbage collected. /// Ensure that this is the only instance of a pointer to the underlying value.
/// Since the drop order for garbage collected structs is undefined that means it is never /// You might want to instead use one of various [cell][`std::cell`] types as the allocated
/// safe to call this function in a [Drop::drop]. /// type
///
/// Do note that this doesn't mean that any particular instance of GcRef has to be marked
/// as reachable during a call to [GCAllocator::gc][`crate::allocator::GCAllocator::gc`]
/// but instead any GcRef instance referring to the same underlying pointer has to be reachable
pub unsafe fn get(&self) -> &T {
unsafe { self.0.as_ref() }
}
/// # Safety
/// The caller needs to ensure that the underlying pointer hasn't been garbage collected.
/// See [GcRef::get] for more details
///
/// The caller needs to ensure that this is the only instance of a pointer to the underlying value
/// (in other words that [Clone] hasn't been called, or that all other clones of the pointer have
/// already been dropped).
///
/// This function is hard(but not impossible) to use without causing UB. Unless you have a
/// really special use case you might want to instead use one of various [cell][`std::cell`]
/// types as the allocated type.
pub unsafe fn get_mut(this: &mut Self) -> &mut T { pub unsafe fn get_mut(this: &mut Self) -> &mut T {
this.0.as_mut() this.0.as_mut()
} }

View file

@ -11,12 +11,11 @@ pub mod test_utils;
#[cfg(test)] #[cfg(test)]
pub(crate) mod tests { pub(crate) mod tests {
use super::allocator::GCAllocator; use super::allocator::GCAllocator;
use super::test_utils::GotDropped; use super::test_utils::GotDropped;
#[test] #[test]
fn gc_allocates_and_frees_structs() { fn it_works() {
let got_dropped = GotDropped::default(); let got_dropped = GotDropped::default();
let mut gc = GCAllocator::default(); let mut gc = GCAllocator::default();

View file

@ -7,7 +7,6 @@ unsafe impl GCTrace for i64 {}
unsafe impl GCTrace for u64 {} unsafe impl GCTrace for u64 {}
unsafe impl GCTrace for f32 {} unsafe impl GCTrace for f32 {}
unsafe impl GCTrace for f64 {} unsafe impl GCTrace for f64 {}
unsafe impl GCTrace for bool {}
unsafe impl GCTrace for isize {} unsafe impl GCTrace for isize {}
unsafe impl GCTrace for usize {} unsafe impl GCTrace for usize {}
unsafe impl GCTrace for String {} unsafe impl GCTrace for String {}

View file

@ -20,10 +20,10 @@ impl Environment {
pub fn update_var(&mut self, name: &str, v: Primitive) -> Option<Primitive> { pub fn update_var(&mut self, name: &str, v: Primitive) -> Option<Primitive> {
if let Some(cur) = self.variables.get_mut(name) { if let Some(cur) = self.variables.get_mut(name) {
Some(std::mem::replace(cur, v)) Some(std::mem::replace(cur, v))
} else if let Some(ref parent) = self.parent {
unsafe { parent.get().borrow_mut().update_var(name, v) }
} else { } else {
None self.parent
.as_ref()
.and_then(|parent| parent.borrow_mut().update_var(name, v))
} }
} }
@ -34,11 +34,9 @@ impl Environment {
pub fn get_var(&self, name: &str) -> Option<Primitive> { pub fn get_var(&self, name: &str) -> Option<Primitive> {
self.variables.get(name).cloned().or_else(|| { self.variables.get(name).cloned().or_else(|| {
if let Some(ref parent) = self.parent { self.parent
unsafe { parent.get().borrow().get_var(name) } .as_ref()
} else { .and_then(|v| (**v).borrow().get_var(name))
None
}
}) })
} }
} }
@ -50,10 +48,10 @@ pub struct World {
impl World { impl World {
pub fn set_var(&mut self, name: String, v: Primitive) -> Option<Primitive> { pub fn set_var(&mut self, name: String, v: Primitive) -> Option<Primitive> {
unsafe { self.env.get().borrow_mut().set_var(name, v) } self.env.borrow_mut().set_var(name, v)
} }
pub fn get_var(&self, name: &str) -> Option<Primitive> { pub fn get_var(&self, name: &str) -> Option<Primitive> {
unsafe { self.env.get().borrow().get_var(name) } self.env.borrow().get_var(name)
} }
} }