WIP: DynAccept trait, Visitor-based GC

DynAccept trait is necessary because we need some kind of Accept trait
that doesn't have generic methods - this is so we can dynamically
dispatch the .accept() method from a &dyn Obj type. I plan to work this
into the regular Accept trait and do away with the DynAccept distinction
entirely.

I'm also experimenting with using visitors to do GC, so that all
references are wrapped in a future GcRef, so they don't have to
implement that as part of their object. The GC will be able to visit any
Obj + ?Sized type, and can have a specific implementation if required.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-05-22 12:04:27 -04:00
parent 18f9810070
commit 7de005b160
10 changed files with 119 additions and 184 deletions

View File

@@ -21,23 +21,12 @@ impl Gc for BasicGc {
self.objects.push(owned); self.objects.push(owned);
} }
fn mark(&mut self, alive: &[DynRef]) { fn mark(&mut self, _alive: &[DynRef]) {
for obj in alive.iter() { todo!()
obj.borrow().mark();
}
// TODO : where should interned strings be marked?
} }
fn sweep(&mut self) { fn sweep(&mut self) {
// sweep todo!()
self.objects.retain(|cell| {
let obj = cell.borrow();
!obj.is_marked()
});
// unmark all objects
self.objects
.iter_mut()
.for_each(|cell| cell.borrow().unmark());
} }
} }

View File

@@ -1,4 +1,4 @@
use crate::{mem::ptr::ObjCell, obj::prelude::*}; use crate::{mem::ptr::ObjCell, obj::prelude::*, visit::{Accept, Visit},};
pub trait Gc { pub trait Gc {
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O>; fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O>;
@@ -9,3 +9,12 @@ pub trait Gc {
fn sweep(&mut self); fn sweep(&mut self);
} }
impl<O> Visit<O> for O
where O: Obj + Accept
{
type Out = ();
fn visit(&mut self, obj: &O) -> Self::Out {
obj.accept(self)
}
}

View File

@@ -1,4 +1,4 @@
use crate::obj::Obj; use crate::{obj::Obj, visit::{DynAccept, Accept, Visit}};
use std::{ use std::{
any, any,
cell::RefCell, cell::RefCell,
@@ -30,13 +30,6 @@ where
} }
} }
impl<O: Obj + ?Sized> AsRef<ObjCell<O>> for ObjRef<O> {
fn as_ref(&self) -> &ObjCell<O> {
// safe because pointer should point at live data assuming GC is working appropriately
unsafe { &*self.as_ptr() }
}
}
impl<O> ObjRef<O> impl<O> ObjRef<O>
where where
O: Obj, O: Obj,
@@ -47,6 +40,13 @@ where
} }
} }
impl<O: Obj + ?Sized> AsRef<ObjCell<O>> for ObjRef<O> {
fn as_ref(&self) -> &ObjCell<O> {
// safe because pointer should point at live data assuming GC is working appropriately
unsafe { &*self.as_ptr() }
}
}
impl<O> Deref for ObjRef<O> impl<O> Deref for ObjRef<O>
where where
O: Obj + ?Sized, O: Obj + ?Sized,
@@ -94,6 +94,14 @@ impl Debug for ObjRef<dyn Obj> {
} }
} }
impl<O> DynAccept for ObjRef<O>
where O: Obj + ?Sized + DynAccept
{
fn accept(&self, visitor: &mut impl Visit<Self, Out=()>) {
todo!()
}
}
// //
// Comparison impls // Comparison impls
// //

View File

@@ -1,6 +1,7 @@
use crate::{ use crate::{
mem::ptr::{DynRef, ObjCell}, mem::ptr::{DynRef, ObjCell},
obj::prelude::*, obj::prelude::*,
visit::Visit,
}; };
use std::{ use std::{
cell::Cell, cell::Cell,
@@ -60,48 +61,17 @@ impl Obj for Attrs {
self.this self.this
} }
fn is_marked(&self) -> bool {
self.marked.get()
}
fn mark(&self) {
if self.is_marked() {
return;
}
self.marked.set(true);
self.attrs.iter().for_each(|(_, v)| v.borrow().mark());
}
fn unmark(&self) {
if !self.is_marked() {
return;
}
self.marked.set(false);
self.attrs.iter().for_each(|(_, v)| v.borrow().unmark());
}
fn as_any(&self) -> &dyn std::any::Any { fn as_any(&self) -> &dyn std::any::Any {
self self
} }
} }
#[test] //impl_accept!(Attrs);
fn test_attrs_new() {
use crate::mem::BasicGc;
let mut gc = BasicGc::default(); impl<G: Gc> Visit<Attrs> for G {
type Out = ();
let attrs_ref = Attrs::new(&mut gc, Default::default()); fn visit(&mut self, _attrs: &Attrs) -> Self::Out {
todo!()
{
let mut attrs = attrs_ref.borrow_mut();
let sym = Sym::new(0);
attrs.insert(sym, attrs_ref.as_dyn());
assert!(ptr::eq(
dbg!(attrs.get(sym).unwrap().as_ptr()),
dbg!(attrs_ref.as_dyn().as_ptr())
// as_dyn() is important here - this will cause the test to fail otherwise
),);
} }
} }

View File

@@ -1,4 +1,4 @@
use crate::obj::prelude::*; use crate::{obj::prelude::*, visit::Visit};
use std::{any::Any, cell::Cell}; use std::{any::Any, cell::Cell};
pub type DictRef = ObjRef<Dict>; pub type DictRef = ObjRef<Dict>;
@@ -24,31 +24,20 @@ impl Obj for Dict {
self.attrs self.attrs
} }
fn is_marked(&self) -> bool {
self.marked.get()
}
fn mark(&self) {
if self.is_marked() {
return;
}
self.marked.set(true);
// TODO: dict
self.attrs.borrow().mark();
todo!()
}
fn unmark(&self) {
if !self.is_marked() {
return;
}
self.marked.set(false);
// TODO: dict
self.attrs.borrow().unmark();
todo!()
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
} }
//impl_accept!(Dict);
impl<G> Visit<Dict> for G
where G: Gc + Visit<Attrs>,
{
type Out = ();
fn visit(&mut self, dict: &Dict) -> Self::Out {
let attrs_ref: &Attrs = &dict.attrs.borrow();
self.visit(attrs_ref);
}
}

View File

@@ -24,15 +24,6 @@ impl Obj for NativeFun {
self.attrs self.attrs
} }
fn is_marked(&self) -> bool {
// native functions are always available
true
}
fn mark(&self) {}
fn unmark(&self) {}
fn as_any(&self) -> &dyn std::any::Any { fn as_any(&self) -> &dyn std::any::Any {
self self
} }
@@ -63,26 +54,6 @@ impl Obj for Fun {
self.attrs self.attrs
} }
fn is_marked(&self) -> bool {
self.marked.get()
}
fn mark(&self) {
if self.is_marked() {
return;
}
self.marked.set(true);
self.attrs.borrow().mark();
}
fn unmark(&self) {
if !self.is_marked() {
return;
}
self.marked.set(false);
self.attrs.borrow().unmark();
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }

View File

@@ -50,10 +50,5 @@ use std::any::Any;
pub trait Obj { pub trait Obj {
fn attrs(&self) -> ObjRef<Attrs>; fn attrs(&self) -> ObjRef<Attrs>;
fn is_marked(&self) -> bool;
fn mark(&self);
fn unmark(&self);
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
} }

View File

@@ -1,4 +1,4 @@
use crate::obj::prelude::*; use crate::{obj::prelude::*, visit::{DynAccept, Visit}};
use derivative::Derivative; use derivative::Derivative;
use std::{any::Any, cell::Cell}; use std::{any::Any, cell::Cell};
@@ -35,27 +35,25 @@ impl Obj for Str {
self.attrs self.attrs
} }
fn is_marked(&self) -> bool {
self.marked.get()
}
fn mark(&self) {
if self.is_marked() {
return;
}
self.marked.set(true);
self.attrs.borrow().mark();
}
fn unmark(&self) {
if !self.is_marked() {
return;
}
self.marked.set(false);
todo!()
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
} }
//impl_accept!(Str);
impl<O> DynAccept for O
where O: Obj + ?Sized
{
fn accept(&self, visitor: &mut impl Visit<Self, Out=()>) {
visitor.visit(self)
}
}
impl<G: Gc> Visit<Str> for G {
type Out = ();
fn visit(&mut self, _s: &Str) -> Self::Out {
todo!()
}
}

View File

@@ -169,3 +169,39 @@ impl Spanned for BaseExpr {
self.span self.span
} }
} }
////////////////////////////////////////////////////////////////////////////////
// Acceptor (visitor) impls
////////////////////////////////////////////////////////////////////////////////
impl_accept!(Stmt);
impl_default_accept!(Stmt : AssignStmt, Expr =>
fn default_accept(&self, visitor: &mut V) -> Out {
match self {
Stmt::Assign(a) => visitor.visit(a),
Stmt::Expr(e) => visitor.visit(e),
}
}
);
impl_accept!(AssignStmt);
impl_accept!(Expr);
impl_default_accept!(Expr: BinExpr, UnExpr, FunCallExpr, IndexExpr, FunExpr, BaseExpr =>
fn default_accept(&self, visitor: &mut V) -> Out {
match self {
Expr::Bin(b) => visitor.visit(b.as_ref()),
Expr::Un(u) => visitor.visit(u.as_ref()),
Expr::FunCall(f) => visitor.visit(f.as_ref()),
Expr::Index(i) => visitor.visit(i.as_ref()),
Expr::Fun(f) => visitor.visit(f.as_ref()),
Expr::Base(b) => visitor.visit(b),
}
}
);
impl_accept!(BinExpr);
impl_accept!(UnExpr);
impl_accept!(FunCallExpr);
impl_accept!(IndexExpr);
impl_accept!(FunExpr);
impl_accept!(BaseExpr);

View File

@@ -1,14 +1,14 @@
use crate::syn::ast::prelude::*; pub trait Visit<A: ?Sized> {
pub trait Visit<A: Accept> {
type Out; type Out;
fn visit(&mut self, acceptor: &A) -> Self::Out; fn visit(&mut self, acceptor: &A) -> Self::Out;
} }
pub trait Accept { pub trait Accept {
fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out;
where }
Self: Sized;
pub trait DynAccept<Out=()> {
fn accept(&self, visitor: &mut impl Visit<Self, Out=Out>);
} }
pub trait DefaultAccept<V: Visit<Self>>: Accept + Sized { pub trait DefaultAccept<V: Visit<Self>>: Accept + Sized {
@@ -18,7 +18,7 @@ pub trait DefaultAccept<V: Visit<Self>>: Accept + Sized {
#[macro_export] #[macro_export]
macro_rules! default_visitor { macro_rules! default_visitor {
($default:ident for $visitor:ty where Out = $out:ty) => { ($default:ident for $visitor:ty where Out = $out:ty) => {
impl crate::visit::Visit<$default> for $visitor { impl $crate::visit::Visit<$default> for $visitor {
type Out = $out; type Out = $out;
fn visit(&mut self, acceptor: &$default) -> Self::Out { fn visit(&mut self, acceptor: &$default) -> Self::Out {
acceptor.default_accept(self) acceptor.default_accept(self)
@@ -30,61 +30,31 @@ macro_rules! default_visitor {
#[macro_export] #[macro_export]
macro_rules! empty_visitor { macro_rules! empty_visitor {
($default:ident for $visitor:ty) => { ($default:ident for $visitor:ty) => {
impl crate::visit::Visit<$default> for $visitor { impl $crate::visit::Visit<$default> for $visitor {
type Out = (); type Out = ();
fn visit(&mut self, _: &$default) -> Self::Out {} fn visit(&mut self, _: &$default) -> Self::Out {}
} }
}; };
} }
#[macro_export]
macro_rules! impl_accept { macro_rules! impl_accept {
($what:ident) => { ($what:ty) => {
impl crate::visit::Accept for $what { impl $crate::visit::Accept for $what {
fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out { fn accept<V: $crate::visit::Visit<Self>>(&self, visitor: &mut V) -> V::Out {
visitor.visit(self) visitor.visit(self)
} }
} }
}; };
} }
#[macro_export]
macro_rules! impl_default_accept { macro_rules! impl_default_accept {
($what:ident : $($requires:ident),+ => $($tail:tt)+) => { ($what:ident : $($requires:ident),+ => $($tail:tt)+) => {
impl<V, Out> DefaultAccept<V> for $what impl<V, Out> $crate::visit::DefaultAccept<V> for $what
where V: Visit<Self, Out=Out> $(+ Visit<$requires, Out=Out>)+ where V: $crate::visit::Visit<Self, Out=Out> $(+ $crate::visit::Visit<$requires, Out=Out>)+
{ {
$($tail)+ $($tail)+
} }
}; };
} }
impl_accept!(Stmt);
impl_default_accept!(Stmt : AssignStmt, Expr =>
fn default_accept(&self, visitor: &mut V) -> Out {
match self {
Stmt::Assign(a) => visitor.visit(a),
Stmt::Expr(e) => visitor.visit(e),
}
}
);
impl_accept!(AssignStmt);
impl_accept!(Expr);
impl_default_accept!(Expr: BinExpr, UnExpr, FunCallExpr, IndexExpr, FunExpr, BaseExpr =>
fn default_accept(&self, visitor: &mut V) -> Out {
match self {
Expr::Bin(b) => visitor.visit(b.as_ref()),
Expr::Un(u) => visitor.visit(u.as_ref()),
Expr::FunCall(f) => visitor.visit(f.as_ref()),
Expr::Index(i) => visitor.visit(i.as_ref()),
Expr::Fun(f) => visitor.visit(f.as_ref()),
Expr::Base(b) => visitor.visit(b),
}
}
);
impl_accept!(BinExpr);
impl_accept!(UnExpr);
impl_accept!(FunCallExpr);
impl_accept!(IndexExpr);
impl_accept!(FunExpr);
impl_accept!(BaseExpr);