Started writing our new Form designed to be used from JIT with repr(C) and packed into a single word, and our own repr(C) Rc implementation to go with it.
This commit is contained in:
194
slj/src/main.rs
194
slj/src/main.rs
@@ -2,12 +2,203 @@
|
|||||||
lalrpop_mod!(pub grammar);
|
lalrpop_mod!(pub grammar);
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::rc::Rc;
|
use std::cell::Cell;
|
||||||
|
//use std::rc::Rc;
|
||||||
|
|
||||||
use sl::eval;
|
use sl::eval;
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
use std::mem::ManuallyDrop;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Rc<T> {
|
||||||
|
ptr: NonNull<RcInner<T>>,
|
||||||
|
phantom: PhantomData<RcInner<T>>
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RcInner<T> {
|
||||||
|
rc: Cell<usize>,
|
||||||
|
data: T,
|
||||||
|
}
|
||||||
|
impl<T> Rc<T> {
|
||||||
|
pub fn new(data: T) -> Rc<T> {
|
||||||
|
let boxed = Box::new(RcInner { rc: Cell::new(1), data });
|
||||||
|
Rc {
|
||||||
|
ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn into_ptr(self) -> *mut RcInner<T> {
|
||||||
|
ManuallyDrop::new(self).ptr.as_ptr() as *mut RcInner<T>
|
||||||
|
}
|
||||||
|
pub fn from_ptr(ptr: *mut RcInner<T>) -> Self {
|
||||||
|
Rc {
|
||||||
|
ptr: NonNull::new(ptr).unwrap(),
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe impl<T: Sync+Send> Send for Rc<T> {}
|
||||||
|
unsafe impl<T: Sync+Send> Sync for Rc<T> {}
|
||||||
|
impl<T> Deref for Rc<T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
let inner = unsafe { self.ptr.as_ref() };
|
||||||
|
&inner.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> Clone for Rc<T> {
|
||||||
|
fn clone(&self) -> Rc<T> {
|
||||||
|
let inner = unsafe { self.ptr.as_ref() };
|
||||||
|
let old = inner.rc.get();
|
||||||
|
inner.rc.set(old + 1);
|
||||||
|
if old > isize::MAX as usize {
|
||||||
|
std::process::abort();
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
ptr: self.ptr,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> Drop for Rc<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let inner = unsafe { self.ptr.as_mut() };
|
||||||
|
let old = inner.rc.get();
|
||||||
|
inner.rc.set(old - 1);
|
||||||
|
if old != 1 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsafe { drop(Box::from_raw(self.ptr.as_ptr())); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub enum Form {
|
||||||
|
Nil,
|
||||||
|
Int(i32),
|
||||||
|
Bool(bool),
|
||||||
|
Symbol(String),
|
||||||
|
Pair(Rc<Form>, Rc<Form>),
|
||||||
|
Closure(Vec<String>, Rc<Form>, Rc<Form>, ID),
|
||||||
|
Prim(Prim),
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#[repr(C)]
|
||||||
|
struct Form {
|
||||||
|
data: *const Form,
|
||||||
|
phantom: PhantomData<Form>
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
struct FormPair {
|
||||||
|
car: Form,
|
||||||
|
cdr: Form,
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* this better be a 64 bit platform
|
||||||
|
* huh, if we only support i32s, then we have a lot more room for tags
|
||||||
|
* 8 byte alignment gets us 3 bits, or uh 8 options
|
||||||
|
* we'll choose 000 for ints to make math easy
|
||||||
|
*
|
||||||
|
* 000 - Int
|
||||||
|
* 001 - Nil
|
||||||
|
* 010 - Bool(false) // this is needlessly wasteful of the bits but hay
|
||||||
|
* 011 - Bool(true)
|
||||||
|
* 100 - Symbol - will want to convert into an Rc around a StringRawParts struct
|
||||||
|
* 101 - Pair - an Rc around a Pair struct
|
||||||
|
* 110 - Closure- eek: Closure(Vec<String>, Rc<Form>, Rc<Form>, ID),
|
||||||
|
* xxxx 111 - Prim (xxxx for which one)
|
||||||
|
*
|
||||||
|
* I don't actually think we need our own repr(C) Vec implementation, at least not for now - we can
|
||||||
|
* make do with a VecRawParts struct (without implementations)
|
||||||
|
*
|
||||||
|
* in both cases, StringRawParts and VecRawParts, we can rebuild slices from the raw parts for
|
||||||
|
* read-only access, which is all we need (until Drop, at which point we should re-constitute them
|
||||||
|
* from their raw parts, which is stable)
|
||||||
|
*/
|
||||||
|
impl Form {
|
||||||
|
fn new_int(x: isize) -> Self {
|
||||||
|
Self { data: (x << 3) as *const Form, phantom: PhantomData }
|
||||||
|
}
|
||||||
|
fn new_nil() -> Self {
|
||||||
|
Self { data: 0b001 as *const Form, phantom: PhantomData }
|
||||||
|
}
|
||||||
|
fn new_bool(b: bool) -> Self {
|
||||||
|
Self { data: (if b { 0b011 } else { 0b010 }) as *const Form, phantom: PhantomData }
|
||||||
|
}
|
||||||
|
fn new_pair(car: Form, cdr: Form) -> Self {
|
||||||
|
let p = Rc::new(FormPair { car, cdr }).into_ptr() as usize;
|
||||||
|
assert!(p & 0b111 == 0);
|
||||||
|
Self { data: (p | 0b101) as *const Form, phantom: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Drop for Form {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
match self.data as usize & 0b111 {
|
||||||
|
0b000 | 0b001 | 0b010 | 0b011 => { println!("dropping simple {self}"); }, // int, nil, false, true
|
||||||
|
0b101 => {
|
||||||
|
// pair
|
||||||
|
let _ = Rc::<FormPair>::from_ptr( (self.data as usize & !0b111) as *mut RcInner<FormPair> );
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl fmt::Display for Form {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.data as usize & 0b111 {
|
||||||
|
0b000 => {
|
||||||
|
write!(f, "{}", self.data as isize >> 3)?;
|
||||||
|
},
|
||||||
|
0b001 => {
|
||||||
|
write!(f, "nil")?;
|
||||||
|
},
|
||||||
|
0b010 => {
|
||||||
|
write!(f, "false")?;
|
||||||
|
},
|
||||||
|
0b011 => {
|
||||||
|
write!(f, "true")?;
|
||||||
|
},
|
||||||
|
0b101 => {
|
||||||
|
write!(f, "pair")?;
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn alias(a: Rc<u64>, b: Rc<u64>) {
|
||||||
|
println!("a: {}, b: {}", *a, *b);
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
// our Form shennigins will only work on 64 bit platforms
|
||||||
|
assert!(std::mem::size_of::<usize>() == 8);
|
||||||
|
|
||||||
|
let x = Rc::new(1);
|
||||||
|
alias(Rc::clone(&x), x);
|
||||||
|
let rc_u64_size = std::mem::size_of::<Rc<u64>>();
|
||||||
|
assert!(rc_u64_size == 8);
|
||||||
|
println!("for our Rc, we have size {}", rc_u64_size);
|
||||||
|
|
||||||
|
let i = Form::new_int(23);
|
||||||
|
let n = Form::new_nil();
|
||||||
|
let bf = Form::new_bool(false);
|
||||||
|
let bt = Form::new_bool(true);
|
||||||
|
|
||||||
|
let p = Form::new_pair(Form::new_int(50), Form::new_nil());
|
||||||
|
println!("{i} {n} {bf} {bt} {p}");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
let input = "
|
let input = "
|
||||||
(begin
|
(begin
|
||||||
(debug 1)
|
(debug 1)
|
||||||
@@ -68,5 +259,6 @@ fn main() -> Result<()> {
|
|||||||
println!("Hello, world: {parsed_input}");
|
println!("Hello, world: {parsed_input}");
|
||||||
let evaled = eval(Rc::clone(&parsed_input))?;
|
let evaled = eval(Rc::clone(&parsed_input))?;
|
||||||
println!("evaled: {evaled}");
|
println!("evaled: {evaled}");
|
||||||
|
*/
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user