Add mem and obj modules, move to nightly

* mem and obj modules are roughly divided between doing memory-specific
  things and object-specific things
* Box::new_uninit() is a nightly feature and it's quite useful, so I'm
  enabling that for now
* Check out src/obj/attrs.rs for possible undefined behavior in the
  Attrs::new() function. I'm sure it'll be just fine.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-05-14 17:10:53 -04:00
parent e233ff1cfc
commit ccb12306d4
15 changed files with 615 additions and 0 deletions

View File

@@ -1,4 +1,9 @@
#![allow(dead_code)]
#![feature(new_uninit)]
mod syn;
mod obj;
mod mem;
use std::{
convert::TryFrom,

71
src/mem/basic.rs Normal file
View File

@@ -0,0 +1,71 @@
use crate::{
mem::{
gc::Gc,
intern::Intern,
ptr::{DynRef, ObjCell, ObjRef},
},
obj::{ctx::ObjCtx, Obj, Str, Sym},
};
use std::{collections::HashMap, ptr::NonNull};
pub struct BasicGc {
objects: Vec<Box<ObjCell<dyn Obj>>>,
strs: HashMap<String, ObjRef<Str>>,
syms: HashMap<String, Sym>,
}
impl Gc for BasicGc {
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O> {
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<O: Obj + 'static>(&mut self, owned: Box<ObjCell<O>>) {
self.objects.push(owned);
}
fn mark(&mut self, alive: &[DynRef]) {
for obj in alive.iter() {
obj.borrow().mark();
}
// TODO : where should interned strings be marked?
}
fn sweep(&mut self) {
// sweep
self.objects.retain(|cell| {
let obj = cell.borrow();
!obj.is_marked()
});
// unmark all objects
self.objects
.iter_mut()
.for_each(|cell| cell.borrow().unmark());
}
}
impl Intern for BasicGc {
fn get_str(&self, s: &str) -> Option<ObjRef<Str>> {
self.strs.get(s).copied()
}
fn add_str(&mut self, ctx: &mut ObjCtx, s: &str) -> ObjRef<Str> {
*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<Sym> {
self.syms.get(s).copied()
}
fn add_sym(&mut self, s: &str) -> Sym {
let len = self.syms.len();
*self.syms.entry(s.to_string())
.or_insert_with(|| len)
}
}

22
src/mem/gc.rs Normal file
View File

@@ -0,0 +1,22 @@
use crate::{
obj::prelude::*,
mem::{
ptr::ObjCell,
intern::Intern,
}
};
pub trait Gc: Intern {
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O>;
fn add_obj<O: Obj + 'static>(&mut self, owned: Box<ObjCell<O>>);
fn mark(&mut self, alive: &[DynRef]) {
for obj in alive.iter() {
obj.borrow_mut().mark();
}
}
fn sweep(&mut self);
}

15
src/mem/intern.rs Normal file
View File

@@ -0,0 +1,15 @@
use crate::{
mem::ptr::ObjRef,
obj::{
ctx::ObjCtx,
Str, Sym,
},
};
pub trait Intern {
fn get_str(&self, s: &str) -> Option<ObjRef<Str>>;
fn add_str(&mut self, ctx: &mut ObjCtx, s: &str) -> ObjRef<Str>;
fn get_sym(&self, s: &str) -> Option<Sym>;
fn add_sym(&mut self, s: &str) -> Sym;
}

16
src/mem/mod.rs Normal file
View File

@@ -0,0 +1,16 @@
mod basic;
pub mod intern;
pub mod gc;
pub mod ptr;
pub use self::basic::BasicGc;
/*
pub mod prelude {
pub use crate::mem::{
alloc::Alloc,
gc::Gc,
ptr::*
}
}
*/

130
src/mem/ptr.rs Normal file
View File

@@ -0,0 +1,130 @@
use crate::obj::Obj;
use std::{
any,
cell::RefCell,
fmt::{self, Debug, Formatter},
ops::Deref,
ptr::NonNull,
};
pub type DynRef = ObjRef<dyn Obj>;
pub struct ObjRef<O>
where O: Obj + ?Sized
{
ptr: NonNull<ObjCell<O>>,
}
impl<O> ObjRef<O>
where O: Obj + ?Sized
{
pub fn new(ptr: NonNull<ObjCell<O>>) -> Self {
ObjRef { ptr }
}
pub fn as_ptr(&self) -> *const ObjCell<O> {
self.ptr.as_ptr()
}
}
impl<O> ObjRef<O>
where O: Obj
{
pub fn as_dyn(&self) -> ObjRef<dyn Obj> {
let ptr = self.as_ptr() as *const ObjCell<dyn Obj>;
ObjRef::new(NonNull::new(ptr as *mut _).unwrap())
}
}
impl<O> Deref for ObjRef<O>
where O: Obj + ?Sized
{
type Target = RefCell<O>;
fn deref(&self) -> &Self::Target {
// Safe, so long as there are no dangling pointers from the GC
unsafe { &*self.as_ptr() }
}
}
impl<O> Clone for ObjRef<O>
where O: Obj + ?Sized
{
fn clone(&self) -> Self {
ObjRef { ptr: self.ptr }
}
}
impl<O> Copy for ObjRef<O>
where O: Obj + ?Sized
{}
impl<O> Debug for ObjRef<O>
where O: Obj + Debug + ?Sized
{
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "<{} object at {:#x}>", any::type_name::<O>(), self.as_ptr() as *const () as usize)
}
}
impl Debug for ObjRef<dyn Obj> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "<? object at {:#x}>", self.as_ptr() as *const () as usize)
}
}
//
// Comparison impls
//
impl<O> PartialEq for ObjRef<O>
where
O: Obj + ?Sized + PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.borrow().eq(&other.borrow())
}
}
impl<O> Eq for ObjRef<O> where O: Obj + ?Sized + Eq {}
impl<O> PartialOrd for ObjRef<O>
where
O: Obj + ?Sized + PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.borrow().partial_cmp(&other.borrow())
}
}
impl<O> Ord for ObjRef<O>
where
O: Obj + ?Sized + Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.borrow().cmp(&other.borrow())
}
}
//
// ObjCell
//
#[derive(Debug, Clone)]
pub struct ObjCell<O: Obj + ?Sized> {
cell: RefCell<O>,
}
impl<O: Obj> ObjCell<O> {
pub fn new(obj: O) -> Self {
ObjCell {
cell: RefCell::new(obj),
}
}
}
impl<O: Obj + ?Sized> Deref for ObjCell<O> {
type Target = RefCell<O>;
fn deref(&self) -> &Self::Target {
&self.cell
}
}

86
src/obj/attrs.rs Normal file
View File

@@ -0,0 +1,86 @@
use crate::{
mem::ptr::{DynRef, ObjCell},
obj::prelude::*,
};
use std::{
cell::Cell,
mem::MaybeUninit,
ptr::{self, NonNull},
};
#[derive(Clone)]
pub struct Attrs {
attrs: Vec<(Sym, DynRef)>,
marked: Cell<bool>,
this: ObjRef<Attrs>,
}
impl Attrs {
pub fn new(ctx: &mut ObjCtx) -> Self {
let obj: Box<ObjCell<Attrs>> = unsafe {
let mut obj: Box<MaybeUninit<ObjCell<Attrs>>> = 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<Attrs>;
obj.as_mut_ptr().write(ObjCell::new(Attrs {
attrs: Default::default(),
marked: Cell::new(false),
this: ObjRef::new(NonNull::new(this as *mut _).unwrap()),
}));
obj.assume_init()
};
let attrs = {
let obj_ref: &Attrs = &obj.borrow();
assert!(
ptr::eq(&*obj as *const _, obj_ref.this.as_ptr()),
"Attr 'this' member does not point to itself"
);
obj_ref.clone()
};
// Add the object to the allocator pool
ctx.gc_mut().add_obj(obj);
attrs
}
}
impl Obj for Attrs {
fn attrs(&self) -> ObjRef<Attrs> {
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 {
self
}
}
#[test]
fn test_attrs_new() {
/*
use crate::mem::*;
let mut ctx = ObjCtx::new(
*/
}

26
src/obj/ctx.rs Normal file
View File

@@ -0,0 +1,26 @@
use crate::mem::{gc::Gc, BasicGc};
pub type DefaultGc = BasicGc;
pub struct ObjCtx<G=DefaultGc>
where
G: Gc,
{
gc: G,
}
impl<G> ObjCtx<G>
where
G: Gc,
{
pub fn new(gc: G) -> Self {
ObjCtx { gc }
}
pub fn gc(&self) -> &G {
&self.gc
}
pub fn gc_mut(&mut self) -> &mut G {
&mut self.gc
}
}

61
src/obj/dict.rs Normal file
View File

@@ -0,0 +1,61 @@
use crate::obj::prelude::*;
use std::{any::Any, cell::Cell};
pub type DictRef = ObjRef<Dict>;
pub struct Dict {
dict: Vec<(DynRef, DynRef)>,
attrs: ObjRef<Attrs>,
marked: Cell<bool>,
}
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!()
/*
Dict {
dict: Default::default(),
attrs: Attrs::new(ctx),
marked: Cell::new(false),
}
*/
}
}
impl Obj for Dict {
fn attrs(&self) -> ObjRef<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 {
self
}
}

13
src/obj/error.rs Normal file
View File

@@ -0,0 +1,13 @@
use crate::mem::ptr::DynRef;
use snafu::Snafu;
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("illegal attr key"))]
AttrKey {
key: DynRef
}
}
pub type Result<T, E = Error> = std::result::Result<T, E>;

44
src/obj/mod.rs Normal file
View File

@@ -0,0 +1,44 @@
pub mod attrs;
pub mod ctx;
pub mod dict;
pub mod error;
//pub mod native_fun;
//pub mod num;
pub mod str;
pub mod sym {
pub type Sym = usize;
}
//pub mod ty;
pub mod prelude {
pub use crate::{
obj::{
Attrs, Dict, DictRef, Str, StrRef, Sym, ObjCtx, Obj,
},
mem::{
ptr::{ObjRef, DynRef},
intern::Intern,
gc::Gc,
}
};
}
pub use self::{
attrs::Attrs,
dict::{Dict, DictRef},
ctx::ObjCtx,
str::{Str, StrRef},
sym::Sym,
};
use crate::mem::ptr::ObjRef;
use std::any::Any;
pub trait Obj {
fn attrs(&self) -> ObjRef<Attrs>;
fn is_marked(&self) -> bool;
fn mark(&self);
fn unmark(&self);
fn as_any(&self) -> &dyn Any;
}

27
src/obj/native_fun.rs Normal file
View File

@@ -0,0 +1,27 @@
use crate::obj::prelude::*;
pub type NativeFunPtr = *const fn();
pub struct NativeFun {
attrs: Attrs,
fn_ptr: NativeFunPtr,
}
impl NativeFun {
pub fn new(ctx: &mut ObjCtx, name: StrRef, fn_ptr: NativeFunPtr) -> Self {
todo!()
/*
let attrs = Attrs::default();
NativeFun {
attrs,
fn_ptr,
}
*/
}
}
/*
impl Obj for NativeFun {
fn get_attr(&self, key: &DynRef) -> Option<DynRef>
}
*/

0
src/obj/num.rs Normal file
View File

64
src/obj/str.rs Normal file
View File

@@ -0,0 +1,64 @@
use crate::obj::prelude::*;
use derivative::Derivative;
use std::{any::Any, cell::Cell};
pub type StrRef = ObjRef<Str>;
#[derive(Derivative)]
#[derivative(PartialEq, PartialOrd, Ord, Eq)]
pub struct Str {
#[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")]
attrs: ObjRef<Attrs>,
contents: String,
#[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")]
marked: Cell<bool>,
}
impl Str {
pub fn new(ctx: &mut ObjCtx, contents: String) -> Self {
todo!()
/*
Str {
attrs: Default::default(),
contents,
marked: Cell::new(false),
}
*/
}
pub fn contents(&self) -> &String {
&self.contents
}
}
impl Obj for Str {
fn attrs(&self) -> ObjRef<Attrs> {
self.attrs
}
fn is_marked(&self) -> bool {
self.marked.get()
}
fn mark(&self) {
if self.is_marked() {
return;
}
self.marked.set(true);
todo!()
}
fn unmark(&self) {
if !self.is_marked() {
return;
}
self.marked.set(false);
todo!()
}
fn as_any(&self) -> &dyn Any {
self
}
}

35
src/obj/ty.rs Normal file
View File

@@ -0,0 +1,35 @@
use crate::obj::prelude::*;
use std::cell::Cell;
pub struct Ty {
marked: Cell<bool>,
this: ObjRef<Ty>,
}
impl Ty {
pub fn new(ctx: &mut ObjCtx) -> Self {
todo!()
}
}
impl Obj for Ty {
fn attrs(&self) -> ObjRef<Attrs> {
todo!()
}
fn is_marked(&self) -> bool {
self.marked.get()
}
fn mark(&self) {
self.marked.set(true);
}
fn unmark(&self) {
self.marked.set(false);
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}