From d5cf39108bc11f4d02331cc793f0f05357b8afe0 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Sat, 16 May 2020 18:46:09 -0400 Subject: [PATCH] Changes all around - objects and GC Signed-off-by: Alek Ratzloff --- src/main.rs | 2 +- src/mem/basic.rs | 39 +++++----- src/mem/gc.rs | 5 +- src/mem/intern.rs | 14 +--- src/mem/mod.rs | 16 ++--- src/mem/ptr.rs | 15 +++- src/obj/attrs.rs | 41 ++++++----- src/obj/ctx.rs | 37 ++++------ src/obj/dict.rs | 11 +-- src/obj/fun.rs | 6 +- src/obj/mod.rs | 22 +++--- src/obj/str.rs | 12 +--- src/vm/frame.rs | 25 +++++-- src/vm/mod.rs | 180 ++++++++++++++++++++++++++-------------------- src/vm/op.rs | 1 + 15 files changed, 223 insertions(+), 203 deletions(-) diff --git a/src/main.rs b/src/main.rs index e1bb2ab..344fb00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ #![allow(dead_code)] -#![feature(new_uninit)] +#![feature(unsize, coerce_unsized, new_uninit)] mod compile; mod syn; diff --git a/src/mem/basic.rs b/src/mem/basic.rs index 32b504e..dcffafe 100644 --- a/src/mem/basic.rs +++ b/src/mem/basic.rs @@ -2,17 +2,15 @@ use crate::{ mem::{ gc::Gc, intern::Intern, - ptr::{DynRef, ObjCell, ObjRef}, + ptr::ObjCell, }, - obj::{ctx::ObjCtx, Obj, Str, Sym}, + obj::prelude::*, }; use std::{collections::HashMap, ptr::NonNull}; #[derive(Default)] pub struct BasicGc { objects: Vec>>, - strs: HashMap>, - syms: HashMap, } impl Gc for BasicGc { @@ -23,7 +21,7 @@ impl Gc for BasicGc { ObjRef::new(NonNull::new(obj_ptr).unwrap()) } - fn add_obj(&mut self, owned: Box>) { + fn add_obj(&mut self, owned: Box>) { self.objects.push(owned); } @@ -47,24 +45,23 @@ impl Gc for BasicGc { } } -impl Intern for BasicGc { - fn get_str(&self, s: &str) -> Option> { - self.strs.get(s).copied() +pub struct BasicIntern { + strs: HashMap>, + syms: HashMap, +} + +impl Intern for BasicIntern { + fn intern_str(&mut self, gc: &mut G, s: &str) -> StrRef { + if let Some(obj_ref) = self.strs.get(s) { + *obj_ref + } else { + todo!("TODO(obj) intern strings - need attrs somehow") + //let s = Str::new(&mut ctx, s.to_string()); + //ctx.gc_mut().alloc(s) + } } - fn add_str(&mut self, ctx: &mut ObjCtx, s: &str) -> ObjRef { - *self.strs.entry(s.to_string()) - .or_insert_with(|| { - let s = Str::new(ctx, s.to_string()); - ctx.gc_mut().alloc(s) - }) - } - - fn get_sym(&self, s: &str) -> Option { - self.syms.get(s).copied() - } - - fn add_sym(&mut self, s: &str) -> Sym { + fn intern_sym(&mut self, s: &str) -> Sym { let len = self.syms.len(); *self.syms.entry(s.to_string()) .or_insert_with(|| len) diff --git a/src/mem/gc.rs b/src/mem/gc.rs index 71534ac..d2befda 100644 --- a/src/mem/gc.rs +++ b/src/mem/gc.rs @@ -2,14 +2,13 @@ use crate::{ obj::prelude::*, mem::{ ptr::ObjCell, - intern::Intern, } }; -pub trait Gc: Intern { +pub trait Gc { fn alloc(&mut self, obj: O) -> ObjRef; - fn add_obj(&mut self, owned: Box>); + fn add_obj(&mut self, owned: Box>); fn mark(&mut self, alive: &[DynRef]); diff --git a/src/mem/intern.rs b/src/mem/intern.rs index 8c36f44..b0a65ca 100644 --- a/src/mem/intern.rs +++ b/src/mem/intern.rs @@ -1,15 +1,7 @@ -use crate::{ - mem::ptr::ObjRef, - obj::{ - ctx::ObjCtx, - Str, Sym, - }, -}; +use crate::obj::prelude::*; pub trait Intern { - fn get_str(&self, s: &str) -> Option>; - fn add_str(&mut self, ctx: &mut ObjCtx, s: &str) -> ObjRef; + fn intern_str(&mut self, gc: &mut G, s: &str) -> StrRef; - fn get_sym(&self, s: &str) -> Option; - fn add_sym(&mut self, s: &str) -> Sym; + fn intern_sym(&mut self, s: &str) -> Sym; } diff --git a/src/mem/mod.rs b/src/mem/mod.rs index c13c41a..f2d9f88 100644 --- a/src/mem/mod.rs +++ b/src/mem/mod.rs @@ -1,16 +1,16 @@ -mod basic; -pub mod intern; +pub mod basic; pub mod gc; +pub mod intern; pub mod ptr; -pub use self::basic::BasicGc; +pub use basic::BasicGc; -/* pub mod prelude { pub use crate::mem::{ - alloc::Alloc, + BasicGc, gc::Gc, - ptr::* - } + intern::Intern, + ptr::{DynRef, ObjRef}, + }; } -*/ + diff --git a/src/mem/ptr.rs b/src/mem/ptr.rs index 32daaf9..b1e697e 100644 --- a/src/mem/ptr.rs +++ b/src/mem/ptr.rs @@ -1,9 +1,10 @@ use crate::obj::Obj; use std::{ - any::{self, Any}, + any, cell::RefCell, fmt::{self, Debug, Formatter}, - ops::Deref, + marker::Unsize, + ops::{CoerceUnsized, Deref}, ptr::NonNull, }; @@ -124,6 +125,16 @@ where } } +impl CoerceUnsized> for ObjRef + where T: Obj + Unsize + ?Sized, + U: Obj + ?Sized +{} + +impl CoerceUnsized> for ObjCell + where T: CoerceUnsized + Obj, + U: Obj +{} + // // ObjCell // diff --git a/src/obj/attrs.rs b/src/obj/attrs.rs index a0c7d38..0544c1c 100644 --- a/src/obj/attrs.rs +++ b/src/obj/attrs.rs @@ -4,28 +4,27 @@ use crate::{ }; use std::{ cell::Cell, - collections::BTreeMap, mem::MaybeUninit, ptr::{self, NonNull}, }; -pub type AttrsMap = BTreeMap; +pub type AttrsRef = ObjRef; pub struct Attrs { - attrs: AttrsMap, + attrs: Ns, marked: Cell, this: ObjRef, } impl Attrs { - pub fn new(ctx: &mut ObjCtx, attrs: BTreeMap) -> ObjRef { + pub fn new(gc: &mut G, attrs: Ns) -> ObjRef { let obj: Box> = unsafe { let mut obj: Box>> = Box::new_uninit(); // maybe UB? taking away the uninit right before it's initialized may be bad let this = &*obj as *const _ as *const ObjCell; obj.as_mut_ptr().write(ObjCell::new(Attrs { - attrs: Default::default(), + attrs, marked: Cell::new(false), this: ObjRef::new(NonNull::new(this as *mut _).unwrap()), })); @@ -43,7 +42,7 @@ impl Attrs { }; // Add the object to the allocator pool - ctx.gc_mut().add_obj(obj); + gc.add_obj(obj); obj_ref } @@ -87,25 +86,25 @@ impl Obj for Attrs { } } -pub struct AttrsBuilder<'ctx> { - ctx: &'ctx mut ObjCtx, - attrs: AttrsMap, +pub struct AttrsBuilder<'i, I: Intern> { + intern: &'i mut I, + attrs: Ns, } -impl<'ctx> AttrsBuilder<'ctx> { - pub fn new(ctx: &'ctx mut ObjCtx) -> Self { - Self::with_base(ctx, Default::default()) +impl<'i, I: Intern> AttrsBuilder<'i, I> { + pub fn new(intern: &'i mut I) -> Self { + Self::with_base(intern, Default::default()) } - pub fn with_base(ctx: &'ctx mut ObjCtx, attrs: AttrsMap) -> Self { + pub fn with_base(intern: &'i mut I, attrs: Ns) -> Self { AttrsBuilder { attrs, - ctx, + intern, } } pub fn attr(self, symbol_name: &str, value: DynRef) -> Self { - let sym = self.ctx.gc_mut().add_sym(symbol_name); + let sym = self.intern.intern_sym(symbol_name); self.attr_sym(sym, value) } @@ -114,9 +113,9 @@ impl<'ctx> AttrsBuilder<'ctx> { self } - pub fn finish(self) -> ObjRef { - let Self { ctx, attrs } = self; - Attrs::new(ctx, attrs) + pub fn finish(self, gc: &mut G) -> ObjRef { + let Self { intern: _, attrs } = self; + Attrs::new(gc, attrs) } } @@ -124,13 +123,13 @@ impl<'ctx> AttrsBuilder<'ctx> { fn test_attrs_new() { use crate::mem::BasicGc; - let mut ctx = ObjCtx::new(BasicGc::default()); + let mut gc = BasicGc::default(); - let attrs_ref = Attrs::new(&mut ctx, Default::default()); + let attrs_ref = Attrs::new(&mut gc, Default::default()); { let mut attrs = attrs_ref.borrow_mut(); - let sym = ctx.gc_mut().add_sym("symbol"); + let sym = gc.add_sym("symbol"); attrs.insert(sym, attrs_ref.as_dyn()); assert!( diff --git a/src/obj/ctx.rs b/src/obj/ctx.rs index 6976069..280ca46 100644 --- a/src/obj/ctx.rs +++ b/src/obj/ctx.rs @@ -1,40 +1,31 @@ use crate::{ - mem::{gc::Gc, ptr::DynRef, BasicGc}, - obj::Sym, + mem::{gc::Gc, BasicGc}, + obj::prelude::*, }; -use std::collections::BTreeMap; pub type DefaultGc = BasicGc; -pub struct ObjCtx +pub struct ObjCtx<'g, 'n, G> where - G: Gc, + G: Gc + 'g, { - gc: G, - globals: BTreeMap, + gc: &'g mut G, + ns: &'n mut Ns, } -impl ObjCtx +impl<'g, 'n, G> ObjCtx<'g, 'n, G> where - G: Gc, + G: Gc + 'g, { - pub fn new(gc: G) -> Self { - ObjCtx { gc, globals: Default::default() } + pub fn new(gc: &'g mut G, ns: &'n mut Ns) -> Self { + ObjCtx { gc, ns } } - pub fn gc(&self) -> &G { - &self.gc + pub fn gc_mut(&'g mut self) -> &'g mut G { + self.gc } - pub fn gc_mut(&mut self) -> &mut G { - &mut self.gc - } - - pub fn globals(&self) -> &BTreeMap { - &self.globals - } - - pub fn globals_mut(&mut self) -> &mut BTreeMap { - &mut self.globals + pub fn ns_mut(&'n mut self) -> &'n mut Ns { + self.ns } } diff --git a/src/obj/dict.rs b/src/obj/dict.rs index 30806d4..74e8178 100644 --- a/src/obj/dict.rs +++ b/src/obj/dict.rs @@ -10,19 +10,12 @@ pub struct Dict { } impl Dict { - // TODO : base types need to be interned. This should probably be stored in a root namespace. - // * How to get the root namespace? - // * ObjCtx object that holds allocator, gc, root namespace, etc..? - // * How to create initial types? - pub fn new(ctx: &mut ObjCtx) -> Self { - todo!() - /* + pub fn new(attrs: AttrsRef) -> Self { Dict { dict: Default::default(), - attrs: Attrs::new(ctx), + attrs, marked: Cell::new(false), } - */ } } diff --git a/src/obj/fun.rs b/src/obj/fun.rs index 8fd86a1..b5ba0d3 100644 --- a/src/obj/fun.rs +++ b/src/obj/fun.rs @@ -4,13 +4,13 @@ use std::{any::Any, cell::Cell, rc::Rc}; pub type NativeFunPtr = fn(argv: Vec); pub struct NativeFun { - attrs: ObjRef, + attrs: AttrsRef, fn_ptr: NativeFunPtr, } impl NativeFun { - pub fn new(ctx: &mut ObjCtx, name: StrRef, fn_ptr: NativeFunPtr) -> Self { - let attrs = Attrs::new(ctx, Default::default()); + pub fn new(attrs: AttrsRef, name: StrRef, fn_ptr: NativeFunPtr) -> Self { + // TODO : clone attrs, add name NativeFun { attrs, fn_ptr, diff --git a/src/obj/mod.rs b/src/obj/mod.rs index 56c4b0b..cd96df6 100644 --- a/src/obj/mod.rs +++ b/src/obj/mod.rs @@ -4,6 +4,13 @@ pub mod dict; pub mod error; pub mod fun; //pub mod num; +pub mod ns { + use crate::{mem::ptr::DynRef, obj::Sym}; + use std::collections::BTreeMap; + + /// A namespace + pub type Ns = BTreeMap; +} pub mod str; pub mod sym { pub type Sym = usize; @@ -12,22 +19,21 @@ pub mod sym { pub mod prelude { pub use crate::{ - obj::{ - Attrs, Dict, DictRef, Fun, NativeFun, Str, StrRef, Sym, ObjCtx, Obj, - }, mem::{ - ptr::{ObjRef, DynRef}, - intern::Intern, gc::Gc, - } + intern::Intern, + ptr::{DynRef, ObjRef}, + }, + obj::{Attrs, AttrsRef, Dict, DictRef, Fun, NativeFun, Ns, Obj, ObjCtx, Str, StrRef, Sym}, }; } pub use self::{ - attrs::Attrs, + attrs::{Attrs, AttrsBuilder, AttrsRef}, ctx::ObjCtx, dict::{Dict, DictRef}, - fun::{NativeFun, Fun}, + fun::{Fun, NativeFun}, + ns::Ns, str::{Str, StrRef}, sym::Sym, }; diff --git a/src/obj/str.rs b/src/obj/str.rs index a187166..bcf5a19 100644 --- a/src/obj/str.rs +++ b/src/obj/str.rs @@ -8,7 +8,7 @@ pub type StrRef = ObjRef; #[derivative(PartialEq, PartialOrd, Ord, Eq)] pub struct Str { #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")] - attrs: ObjRef, + attrs: AttrsRef, contents: String, @@ -17,20 +17,14 @@ pub struct Str { } impl Str { - pub fn new(ctx: &mut ObjCtx, contents: String) -> Self { + pub fn new(attrs: AttrsRef, contents: String) -> Self { Str { - attrs: Self::type_attrs(ctx), + attrs, contents, marked: Cell::new(false), } } - fn type_attrs(ctx: &mut ObjCtx) -> ObjRef { - // TODO need global namespace - // TODO need upcast from dyn to static - todo!() - } - pub fn contents(&self) -> &String { &self.contents } diff --git a/src/vm/frame.rs b/src/vm/frame.rs index 043e51f..dda8554 100644 --- a/src/vm/frame.rs +++ b/src/vm/frame.rs @@ -1,17 +1,26 @@ -use crate::obj::prelude::*; -use std::collections::BTreeMap; +use crate::{ + obj::prelude::*, + vm::op::Op, +}; +use std::rc::Rc; -#[derive(Default)] pub struct Frame { stack: Vec, ip: usize, return_value: Option, - locals: BTreeMap, + locals: Ns, + ops: Rc>, } impl Frame { - pub fn new() -> Self { - Default::default() + pub fn new(ops: Rc>) -> Self { + Frame { + stack: Default::default(), + ip: 0, + return_value: None, + locals: Default::default(), + ops, + } } pub fn push(&mut self, obj_ref: DynRef) { @@ -45,5 +54,9 @@ impl Frame { pub fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option { self.locals.insert(sym, obj_ref) } + + pub fn ops(&self) -> &Rc> { + &self.ops + } } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 53dedb2..05ee395 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -3,6 +3,7 @@ pub mod frame; use crate::{ obj::prelude::*, + mem::gc::Gc, vm::{ op::Op, frame::Frame, @@ -10,122 +11,145 @@ use crate::{ }; use std::rc::Rc; -pub struct State { +fn root_ns(intern: &mut I, gc: &mut G) -> Ns { + let mut ns: Ns = Default::default(); + ns.insert(intern.intern_sym("Unit"), Attrs::new(gc, Default::default())); + ns +} + +pub struct State { + intern: I, + gc: G, + root_ns: Ns, frames: Vec, } -impl State { - pub fn new() -> Self { - State { frames: Default::default(), } +impl State { + pub fn new(mut intern: I, mut gc: G) -> Self { + let root_ns = root_ns(&mut intern, &mut gc); + State { intern, gc, root_ns, frames: Default::default(), } } - fn frame(&self) -> &Frame { + pub fn frames(&self) -> &Vec { + &self.frames + } + + pub fn frames_mut(&mut self) -> &mut Vec { + &mut self.frames + } + + pub fn frame(&self) -> &Frame { self.frames .last() .unwrap() } - fn frame_mut(&mut self) -> &mut Frame { + pub fn frame_mut(&mut self) -> &mut Frame { self.frames .last_mut() .unwrap() } - fn push_stack(&mut self, value: DynRef) { + pub fn push_stack(&mut self, value: DynRef) { self.frame_mut() .push(value); } - fn pop_stack(&mut self) -> Option { + pub fn pop_stack(&mut self) -> Option { self.frame_mut() .pop() } - fn ip(&self) -> usize { + pub fn ip(&self) -> usize { self.frame().ip() } - fn set_ip(&mut self, ip: usize) { + pub fn set_ip(&mut self, ip: usize) { self.frame_mut().set_ip(ip); } - fn get_local(&self, sym: Sym) -> Option { + pub fn get_local(&self, sym: Sym) -> Option { self.frame().get_local(sym) } - fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option { + pub fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option { self.frame_mut().set_local(sym, obj_ref) } - pub fn run(&mut self, ops: Rc>) { - self.frames.push(Default::default()); - while self.ip() < ops.len() { - let mut next_ip = self.ip() + 1; - match &ops[self.ip()] { - Op::Push(sym) => { - // TODO - local not found - let obj_ref = self.get_local(*sym) - .expect("TODO - local not found"); - self.push_stack(obj_ref); - } - Op::Pop(sym) => { - // stack should not underflow - let obj_ref = self.pop_stack() - .expect("misaligned stack for pop"); - if let Some(sym) = *sym { - self.set_local(sym, obj_ref); - } - } - Op::GetAttr(sym) => { - let top = self.pop_stack() - .expect("misaligned stack for getattrs"); - let obj_ref = { - let top_ref = top.borrow(); - let attrs = top_ref.attrs(); - let attrs_ref = attrs.borrow(); - // TODO - local not found - attrs_ref.get(*sym) - .expect("TODO - local not found") - }; - self.push_stack(obj_ref); - } - Op::Call(argc) => { - let fun = self.pop_stack() - .expect("misaligned stack for function call"); - let mut argv = Vec::with_capacity(*argc); - for i in 0 .. *argc { - let arg = self.pop_stack() - .expect("misaligned stack for argv"); - argv.push(arg); - } - // reverse since arguments are pushed in order of being passed - argv.reverse(); + pub fn ops(&self) -> &Rc> { + self.frame().ops() + } - // call function - // TODO - call the function indirectly? - // - // problem: downcast_ref returns a reference bound by the lifetime of the - // function (because of the ref cell). This keeps the fun object borrowed, - // which means any attempts to modify the function while it is running will - // cause the VM to panic. - // - // possible solution: - // pop the function object, and then determine which function to call on the - // object (possibly after downcasting?) - // - // TODO - // Figure out a way to either call a native function with NativeFun::call, or - // call a user function with Fun::code() - if let Some(fun) = fun.borrow().as_any().downcast_ref::() { - } else if let Some(fun) = fun.borrow().as_any().downcast_ref::() { - } else { - todo!("TODO - not a function") - } - todo!() + pub fn resume(&mut self) { + while !self.frames().is_empty() { + self.resume_fun(); + let _frame = self.frames_mut().pop().unwrap(); + // Push return value? + } + } + + pub fn resume_fun(&mut self) { + while self.ip() < self.ops().len() { + self.step(); + } + } + + pub fn step(&mut self) { + let mut next_ip = self.ip() + 1; + match self.ops()[self.ip()] { + Op::Push(sym) => { + // TODO - local not found + let obj_ref = self.get_local(sym) + .expect("TODO - local not found"); + self.push_stack(obj_ref); + } + Op::Pop(sym) => { + // stack should not underflow + let obj_ref = self.pop_stack() + .expect("misaligned stack for pop"); + if let Some(sym) = sym { + self.set_local(sym, obj_ref); } } - self.set_ip(next_ip); + Op::GetAttr(sym) => { + let top = self.pop_stack() + .expect("misaligned stack for getattrs"); + let obj_ref = { + let top_ref = top.borrow(); + let attrs = top_ref.attrs(); + let attrs_ref = attrs.borrow(); + // TODO - local not found + attrs_ref.get(sym) + .expect("TODO - local not found") + }; + self.push_stack(obj_ref); + } + Op::Call(argc) => { + let fun = self.pop_stack() + .expect("misaligned stack for function call"); + let mut argv = Vec::with_capacity(argc); + for _ in 0 .. argc { + let arg = self.pop_stack() + .expect("misaligned stack for argv"); + argv.push(arg); + } + // reverse since arguments are pushed in order of being passed + argv.reverse(); + + // TODO + // move ops pointer to the stack frame + if let Some(_fun) = fun.borrow().as_any().downcast_ref::() { + self.set_ip(next_ip); + next_ip = 0; + todo!("New stack frame"); + } else if let Some(_fun) = fun.borrow().as_any().downcast_ref::() { + todo!(); + } else { + todo!("TODO - not a function"); + } + + } } - self.frames.pop(); + self.set_ip(next_ip); } } diff --git a/src/vm/op.rs b/src/vm/op.rs index 5f047d5..0352a1c 100644 --- a/src/vm/op.rs +++ b/src/vm/op.rs @@ -6,6 +6,7 @@ use crate::obj::Sym; // * ops deal with symbols directly // * stack values are either obj references or symbols +#[derive(Clone, Copy)] pub enum Op { /// Push a value from a symbol Push(Sym),