From c5e1dca7ac323ee39c69f491f75a6d290f87c951 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Fri, 22 May 2020 19:19:12 -0400 Subject: [PATCH] Add VisitObj and Obj::accept(&self, ..) method - VisitObj is for visiting object instances and dyn objects (and thus dynamically dispatching accept) - Obj::accept method is used for dispatching to the specific visitor method - GcMark ZST added for visiting/marking living objects Signed-off-by: Alek Ratzloff --- src/compile/block.rs | 83 +++++++++++++++++++++++++++++++++----------- src/main.rs | 2 +- src/mem/basic.rs | 19 +++------- src/mem/gc.rs | 53 +++++++++++++++++++++++++--- src/mem/ptr.rs | 20 ++++++++--- src/obj/attrs.rs | 20 ++++------- src/obj/dict.rs | 18 +++++++--- src/obj/fun.rs | 8 +++++ src/obj/mod.rs | 8 +++-- src/obj/str.rs | 17 ++++----- src/obj/visit.rs | 14 ++++++++ 11 files changed, 188 insertions(+), 74 deletions(-) create mode 100644 src/obj/visit.rs diff --git a/src/compile/block.rs b/src/compile/block.rs index 1250b46..913e5f9 100644 --- a/src/compile/block.rs +++ b/src/compile/block.rs @@ -1,7 +1,6 @@ use crate::{ compile::{ctx::Ctx, error::*, ir}, - syn::{ast::*, op::BinOp, span::*}, - visit::*, + syn::ast::*, }; // basic block @@ -9,8 +8,39 @@ pub enum Block { Body(ir::Body), Blocks(Vec), } - /* + * Current problem: + * Visiting a TranslateAst would generally return the IR directly per-function. However, returning + * a different value type per Acceptor would make it impossible to have &dyn Acceptor refs, which + * is needed for visitor-based GC. + * + * Ideas: + * - Remove Visit::Out return value, and instead expect that the acceptor implementation to report + * anything new to its visitor. Visitors/acceptors that require returning an error should use + * TryVisit and TryAccept. + * - Doesn't play nicely with something that might want to return something else. + * - TranslateAst doesn't necessarily need to be a Visitor, except for the context + * - Can we just fake it with TryFrom? + * impl TryFrom<(&'_ mut Ctx, ast::Stmt)> for ir::Stmt { ... } + * + */ + +trait ToIr { + fn to_ir(&self, ctx: &mut Ctx) -> Result; +} + +trait FromAst: Sized { + fn from_ast(other: &A, ctx: &mut Ctx) -> Result; +} + +impl FromAst for I + where A: ToIr +{ + fn from_ast(other: &A, ctx: &mut Ctx) -> Result { + other.to_ir(ctx) + } +} + //////////////////////////////////////////////////////////////////////////////// // TranslateAst //////////////////////////////////////////////////////////////////////////////// @@ -25,27 +55,40 @@ impl<'c, 't> TranslateAst<'c, 't> { TranslateAst { ctx, text } } - pub fn translate(&mut self, _ast: &Vec) -> Result { - todo!() - } - - fn visit_lhs_expr(&mut self, expr: &Expr) -> Result { - match expr { - Expr::Bin(b) if b.op == BinOp::Dot => todo!(), - Expr::Base(BaseExpr { - kind: BaseExprKind::Ident, - .. - }) => { - let _name = expr.text_at(self.text); - //let name_id = self.ctx. - todo!() - //Ok(ir::Lhs::Name( - } - _ => Err(Error::InvalidLhs { span: expr.span() }), + pub fn translate(&mut self, ast: &Vec) -> Result { + let mut body = Vec::new(); + for stmt in ast.iter() { + body.push(stmt.to_ir(self.ctx)?); } + Ok(body) } } +impl ToIr for Stmt { + fn to_ir(&self, _ctx: &mut Ctx) -> Result { + todo!() + } +} + +impl ToIr for AssignStmt { + fn to_ir(&self, _ctx: &mut Ctx) -> Result { + todo!() + } +} + +impl ToIr for Expr { + fn to_ir(&self, _ctx: &mut Ctx) -> Result { + todo!() + } +} + +impl ToIr for Expr { + fn to_ir(&self, _ctx: &mut Ctx) -> Result { + todo!() + } +} + +/* impl Visit for TranslateAst<'_, '_> { type Out = Result; diff --git a/src/main.rs b/src/main.rs index fb42689..ff9ffd8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ #![allow(dead_code)] -#![feature(unsize, coerce_unsized, new_uninit)] +#![feature(unsize, coerce_unsized, new_uninit, box_into_pin)] #[macro_use] mod visit; mod compile; diff --git a/src/mem/basic.rs b/src/mem/basic.rs index 1db4857..8681f66 100644 --- a/src/mem/basic.rs +++ b/src/mem/basic.rs @@ -2,31 +2,20 @@ use crate::{ mem::{gc::Gc, ptr::ObjCell}, obj::prelude::*, }; -use std::ptr::NonNull; +use std::pin::Pin; #[derive(Default)] pub struct BasicGc { - objects: Vec>>, + objects: Vec>>>, } impl Gc for BasicGc { - fn alloc(&mut self, obj: O) -> ObjRef { - let obj_cell = Box::new(ObjCell::new(obj)); - let obj_ptr = &*obj_cell as *const _ as *mut _; - self.objects.push(obj_cell); - ObjRef::new(NonNull::new(obj_ptr).unwrap()) - } - - fn add_obj(&mut self, owned: Box>) { + fn add_obj(&mut self, owned: Pin>>) { self.objects.push(owned); } - fn mark(&mut self, _alive: &[DynRef]) { - todo!() - } - fn sweep(&mut self) { - todo!() + self.objects.retain(|cell| cell.is_marked()) } } diff --git a/src/mem/gc.rs b/src/mem/gc.rs index de52e17..af7c66c 100644 --- a/src/mem/gc.rs +++ b/src/mem/gc.rs @@ -1,11 +1,56 @@ -use crate::{mem::ptr::ObjCell, obj::prelude::*, visit::{Accept, Visit},}; +use crate::{mem::ptr::ObjCell, obj::prelude::*}; +use std::pin::Pin; pub trait Gc { - fn alloc(&mut self, obj: O) -> ObjRef; + fn alloc(&mut self, obj: O) -> ObjRef { + let obj_cell = Box::pin(ObjCell::new(obj)); + let obj_ptr = &*obj_cell as *const _ as *mut _; + self.add_obj(obj_cell); + ObjRef::new(std::ptr::NonNull::new(obj_ptr).unwrap()) + } - fn add_obj(&mut self, owned: Box>); + fn add_obj(&mut self, owned: Pin>>); - fn mark(&mut self, alive: &[DynRef]); + fn mark(&mut self, alive: &[DynRef]) { + alive.iter() + .copied() + .for_each(|obj| GcMark.visit(obj)); + } fn sweep(&mut self); } + +pub struct GcMark; + +impl VisitObj for GcMark { + fn visit(&mut self, obj: DynRef) { + if obj.is_marked() { + return; + } + obj.set_marked(true); + obj.borrow().accept(self) + } + + fn visit_attrs(&mut self, attrs: &Attrs) { + attrs.inner() + .values() + .copied() + .for_each(|obj| { + self.visit(obj); + }); + } + + fn visit_dict(&mut self, d: &Dict) { + d.dict() + .iter() + .for_each(|(k, v)| { + self.visit(*k); + self.visit(*v); + }); + self.visit(d.attrs()); + } + + fn visit_str(&mut self, s: &Str) { + self.visit(s.attrs()) + } +} diff --git a/src/mem/ptr.rs b/src/mem/ptr.rs index 32957b9..7abdeab 100644 --- a/src/mem/ptr.rs +++ b/src/mem/ptr.rs @@ -1,7 +1,7 @@ use crate::obj::Obj; use std::{ any, - cell::RefCell, + cell::{Cell, RefCell}, fmt::{self, Debug, Formatter}, marker::Unsize, ops::{CoerceUnsized, Deref}, @@ -51,7 +51,7 @@ impl Deref for ObjRef where O: Obj + ?Sized, { - type Target = RefCell; + type Target = ObjCell; fn deref(&self) -> &Self::Target { // Safe, so long as there are no dangling pointers from the GC @@ -140,22 +140,34 @@ where { } -// +//////////////////////////////////////////////////////////////////////////////// // ObjCell -// +//////////////////////////////////////////////////////////////////////////////// #[derive(Debug, Clone)] pub struct ObjCell { + marked: Cell, cell: RefCell, } impl ObjCell { pub fn new(obj: O) -> Self { ObjCell { + marked: Cell::new(false), cell: RefCell::new(obj), } } } +impl ObjCell { + pub fn is_marked(&self) -> bool { + self.marked.get() + } + + pub fn set_marked(&self, marked: bool) { + self.marked.set(marked); + } +} + impl Deref for ObjCell { type Target = RefCell; diff --git a/src/obj/attrs.rs b/src/obj/attrs.rs index c3272d4..7beb52f 100644 --- a/src/obj/attrs.rs +++ b/src/obj/attrs.rs @@ -1,7 +1,6 @@ use crate::{ mem::ptr::{DynRef, ObjCell}, obj::prelude::*, - visit::Visit, }; use std::{ cell::Cell, @@ -42,10 +41,14 @@ impl Attrs { }; // Add the object to the allocator pool - gc.add_obj(obj); + gc.add_obj(Box::into_pin(obj)); obj_ref } + pub fn inner(&self) -> &Ss { + &self.attrs + } + pub fn insert(&mut self, sym: Sym, value: DynRef) -> Option { self.attrs.insert(sym, value) } @@ -64,17 +67,8 @@ impl Obj for Attrs { fn as_any(&self) -> &dyn std::any::Any { self } -} -/* -impl_accept!(Attrs); - -impl Visit for G { - type Out = (); - - fn visit(&mut self, attrs: &Attrs) -> Self::Out { - attrs.attrs.values() - .for_each(|obj| obj.accept(self)); + fn accept(&self, visitor: &mut dyn VisitObj) { + visitor.visit_attrs(self); } } -*/ diff --git a/src/obj/dict.rs b/src/obj/dict.rs index f3d6716..48989ee 100644 --- a/src/obj/dict.rs +++ b/src/obj/dict.rs @@ -1,12 +1,11 @@ -use crate::{obj::prelude::*, visit::Visit}; -use std::{any::Any, cell::Cell}; +use crate::obj::prelude::*; +use std::any::Any; pub type DictRef = ObjRef; pub struct Dict { dict: Vec<(DynRef, DynRef)>, attrs: ObjRef, - marked: Cell, } impl Dict { @@ -14,9 +13,16 @@ impl Dict { Dict { dict: Default::default(), attrs, - marked: Cell::new(false), } } + + pub fn dict(&self) -> &Vec<(DynRef, DynRef)> { + &self.dict + } + + pub fn dict_mut(&mut self) -> &mut Vec<(DynRef, DynRef)> { + &mut self.dict + } } impl Obj for Dict { @@ -27,4 +33,8 @@ impl Obj for Dict { fn as_any(&self) -> &dyn Any { self } + + fn accept(&self, visitor: &mut dyn VisitObj) { + visitor.visit_dict(self); + } } diff --git a/src/obj/fun.rs b/src/obj/fun.rs index 3ebd120..cabf29d 100644 --- a/src/obj/fun.rs +++ b/src/obj/fun.rs @@ -27,6 +27,10 @@ impl Obj for NativeFun { fn as_any(&self) -> &dyn std::any::Any { self } + + fn accept(&self, _: &mut dyn VisitObj) { + todo!("visit NativeFun"); + } } pub struct Fun { @@ -57,4 +61,8 @@ impl Obj for Fun { fn as_any(&self) -> &dyn Any { self } + + fn accept(&self, _: &mut dyn VisitObj) { + todo!("visit Fun"); + } } diff --git a/src/obj/mod.rs b/src/obj/mod.rs index e431c29..19faff0 100644 --- a/src/obj/mod.rs +++ b/src/obj/mod.rs @@ -20,6 +20,7 @@ pub mod ns { } pub mod str; pub mod sym; +pub mod visit; pub mod prelude { pub use crate::{ @@ -30,7 +31,7 @@ pub mod prelude { }, obj::{ Attrs, AttrsRef, Dict, DictRef, Fun, NameId, NativeFun, Ns, Obj, ObjCtx, Ss, Str, - StrRef, Sym, + StrRef, Sym, VisitObj, }, }; } @@ -44,13 +45,14 @@ pub use self::{ ns::{Ns, Ss}, str::{Str, StrRef}, sym::Sym, + visit::VisitObj, }; use crate::mem::ptr::ObjRef; -use crate::visit::*; use std::any::Any; pub trait Obj { fn attrs(&self) -> ObjRef; fn as_any(&self) -> &dyn Any; -} + fn accept(&self, visitor: &mut dyn VisitObj); +} diff --git a/src/obj/str.rs b/src/obj/str.rs index 77647fb..ae12d6c 100644 --- a/src/obj/str.rs +++ b/src/obj/str.rs @@ -1,6 +1,6 @@ -use crate::{obj::prelude::*, visit::Visit}; +use crate::obj::prelude::*; use derivative::Derivative; -use std::{any::Any, cell::Cell}; +use std::any::Any; pub type StrRef = ObjRef; @@ -11,18 +11,11 @@ pub struct Str { attrs: AttrsRef, contents: String, - - #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")] - marked: Cell, } impl Str { pub fn new(attrs: AttrsRef, contents: String) -> Self { - Str { - attrs, - contents, - marked: Cell::new(false), - } + Str { attrs, contents } } pub fn contents(&self) -> &String { @@ -38,4 +31,8 @@ impl Obj for Str { fn as_any(&self) -> &dyn Any { self } + + fn accept(&self, visitor: &mut dyn VisitObj) { + visitor.visit_str(self); + } } diff --git a/src/obj/visit.rs b/src/obj/visit.rs new file mode 100644 index 0000000..0904bc7 --- /dev/null +++ b/src/obj/visit.rs @@ -0,0 +1,14 @@ +use crate::obj::prelude::*; + +pub trait VisitObj { + fn visit(&mut self, obj: DynRef) where Self: Sized { + obj.borrow().accept(self) + } + + fn visit_attrs(&mut self, attrs: &Attrs); + + fn visit_str(&mut self, s: &Str); + + fn visit_dict(&mut self, d: &Dict); +} +