Skip to content

Commit

Permalink
Introduce Gc object
Browse files Browse the repository at this point in the history
  • Loading branch information
95th committed May 6, 2020
1 parent 516955c commit acf621b
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 58 deletions.
1 change: 1 addition & 0 deletions src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::alloc::{AllocErr, AllocInit, AllocRef, Global, Layout, MemoryBlock, Rea
use std::cell::RefCell;
use std::ptr::NonNull;

pub use alloc_wg::boxed::Box;
pub use alloc_wg::string::String;
pub use alloc_wg::vec::Vec;

Expand Down
2 changes: 1 addition & 1 deletion src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ impl<'a, 'b, A: Alloc> CompileSession<'a, 'b, A> {
fn end_compile(&mut self) {
self.emit_return();
if log_enabled!(Level::Trace) {
chunk!(self).disassemble("code", self.strings);
chunk!(self).disassemble("code");
}
self.locals.truncate(self.stack_top);
}
Expand Down
25 changes: 9 additions & 16 deletions src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use crate::alloc::Alloc;
use crate::chunk::{Chunk, OpCode};
use crate::intern::StringPool;
use num_traits::FromPrimitive;
use std::fmt::{Display, Write};

impl<A: Alloc> Chunk<A> {
pub fn disassemble(&self, name: impl Display, strings: &StringPool<A>) {
pub fn disassemble(&self, name: impl Display) {
trace!("== {} ==", name);

let mut offset = 0;
while offset < self.code.len() {
offset = self.disassemble_instr(offset, strings);
offset = self.disassemble_instr(offset);
}
}

pub fn disassemble_instr(&self, mut offset: usize, strings: &StringPool<A>) -> usize {
pub fn disassemble_instr(&self, mut offset: usize) -> usize {
let buf = &mut format!("{:04}", offset);

if offset > 0 && self.lines[offset] == self.lines[offset - 1] {
Expand All @@ -38,7 +37,7 @@ impl<A: Alloc> Chunk<A> {
| Equal | Greater | Less | Print | Pop => self.simple_instr(opcode, offset, buf),

Constant | GetGlobal | SetGlobal | DefineGlobal => {
self.constant_instr(opcode, offset, buf, strings)
self.constant_instr(opcode, offset, buf)
}

SetLocal | GetLocal | Call => self.byte_instr(opcode, buf, offset),
Expand All @@ -52,7 +51,7 @@ impl<A: Alloc> Chunk<A> {
let constant = self.code[offset];
offset += 1;
write!(buf, "{:-16?} {:4} ", opcode, constant).unwrap();
self.write_value(constant, buf, strings);
self.write_value(constant, buf);
offset
}
};
Expand Down Expand Up @@ -86,20 +85,14 @@ impl<A: Alloc> Chunk<A> {
offset + 3
}

fn constant_instr(
&self,
opcode: OpCode,
offset: usize,
buf: &mut String,
strings: &StringPool<A>,
) -> usize {
fn constant_instr(&self, opcode: OpCode, offset: usize, buf: &mut String) -> usize {
let constant = self.code[offset + 1];
write!(buf, "{:-16?} {:4} ", opcode, constant).unwrap();
self.write_value(constant, buf, strings);
self.write_value(constant, buf);
offset + 2
}

fn write_value(&self, value_idx: u8, buf: &mut String, strings: &StringPool<A>) {
self.values[value_idx as usize].write(buf, strings).unwrap()
fn write_value(&self, value_idx: u8, buf: &mut String) {
self.values[value_idx as usize].write(buf).unwrap()
}
}
28 changes: 9 additions & 19 deletions src/intern.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::alloc::{Alloc, String, Vec};
use std::collections::HashMap;
use crate::object::Gc;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use std::mem;

pub struct StringPool<A: Alloc> {
map: HashMap<Ptr<str>, u32>,
vec: Vec<Ptr<str>, A>,
map: HashSet<Ptr<str>>,
curr_buf: String<A>,
full: Vec<String<A>, A>,
alloc: A,
Expand All @@ -14,37 +14,27 @@ pub struct StringPool<A: Alloc> {
impl<A: Alloc> StringPool<A> {
pub fn new(alloc: A) -> Self {
Self {
map: HashMap::new(),
vec: Vec::new_in(alloc),
map: HashSet::new(),
curr_buf: String::new_in(alloc),
full: Vec::new_in(alloc),
alloc,
}
}

pub fn intern<S: AsRef<str>>(&mut self, name: S) -> u32 {
pub fn intern<S: AsRef<str>>(&mut self, name: S) -> Gc<str> {
let name = name.as_ref();
if let Some(&id) = self.map.get(&Ptr(name)) {
return id;
return Gc::from_raw(id.0);
}
let name = self.alloc(name);
let id = self.map.len() as u32;
self.map.insert(name, id);
self.vec.push(name);
self.map.insert(name);

debug_assert!(self.lookup(id) == name.get());
debug_assert!(self.intern(name.get()) == id);

id
}

pub fn lookup(&self, id: u32) -> &str {
self.vec[id as usize].get()
debug_assert!(self.intern(name.get()) == Gc::from_raw(name.0));
Gc::from_raw(name.0)
}

pub fn clear(&mut self) {
self.map.clear();
self.vec.clear();
self.curr_buf.clear();
self.full.clear();
}
Expand Down
44 changes: 42 additions & 2 deletions src/object.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,55 @@
use crate::alloc::{Alloc, String};
use crate::alloc::{Alloc, Box, String};
use crate::chunk::Chunk;
use crate::intern::StringPool;
use crate::value::Value;
use std::cell::UnsafeCell;
use std::fmt;
use std::ptr::NonNull;
use std::rc::Rc;

pub type NativeFn<A> = fn(&[Value<A>]) -> Value<A>;

#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Gc<T: ?Sized> {
value: NonNull<UnsafeCell<T>>,
}

impl<T: ?Sized> Clone for Gc<T> {
fn clone(&self) -> Self {
Self { value: self.value }
}
}

impl<T: ?Sized> Copy for Gc<T> {}

impl<T> Gc<T> {
pub fn new(value: T, alloc: impl Alloc) -> Self {
let value = Box::into_raw_non_null(Box::new_in(UnsafeCell::new(value), alloc));
Gc { value }
}

pub fn as_mut(&mut self) -> &mut T {
unsafe { &mut *self.value.as_mut().get() }
}
}

impl<T: ?Sized> Gc<T> {
pub fn from_raw(ptr: *const T) -> Self {
unsafe {
Gc {
value: std::mem::transmute(ptr),
}
}
}

pub fn as_ref(&self) -> &T {
unsafe { &*self.value.as_ref().get() }
}
}

#[derive(Clone)]
pub enum Object<A: Alloc> {
String(u32),
String(Gc<str>),
Function(Rc<Function<A>>),
NativeFn(NativeFn<A>),
Closure(ClosureFn<A>),
Expand Down
9 changes: 4 additions & 5 deletions src/value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::alloc::Alloc;
use crate::intern::StringPool;
use crate::object::{Function, Object};
use crate::object::{Function, Gc, Object};
use std::fmt;
use std::rc::Rc;

Expand Down Expand Up @@ -66,7 +65,7 @@ impl<A: Alloc> Value<A> {
impl_as!(as_boolean, Self::Boolean(x), *x, bool);
impl_as!(as_double, Self::Double(x), *x, f64);
impl_as!(as_object, Self::Object(x), x, &Object<A>);
impl_as!(as_string, Self::Object(Object::String(x)), *x, u32);
impl_as!(as_string, Self::Object(Object::String(x)), *x, Gc<str>);
impl_as!(
as_function,
Self::Object(Object::Function(x)),
Expand All @@ -82,12 +81,12 @@ impl_from! {
}

impl<A: Alloc> Value<A> {
pub fn write(&self, mut w: impl fmt::Write, strings: &StringPool<A>) -> fmt::Result {
pub fn write(&self, mut w: impl fmt::Write) -> fmt::Result {
match self {
Value::Nil => write!(w, "nil"),
Value::Boolean(x) => write!(w, "{}", x),
Value::Double(x) => write!(w, "{}", x),
Value::Object(Object::String(x)) => write!(w, "{}", strings.lookup(*x)),
Value::Object(Object::String(x)) => write!(w, "{}", x.as_ref()),
Value::Object(Object::Function(x)) => write!(w, "{}", x),
Value::Object(Object::NativeFn(_)) => write!(w, "<native fn>"),
Value::Object(Object::Closure(x)) => write!(w, "{}", x.function),
Expand Down
25 changes: 10 additions & 15 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::alloc::{Alloc, Vec};
use crate::chunk::OpCode;
use crate::compile::{Compiler, FunctionKind};
use crate::intern::StringPool;
use crate::object::{ClosureFn, NativeFn, Object};
use crate::object::{ClosureFn, Gc, NativeFn, Object};
use crate::value::Value;
use crate::Error;
use log::Level;
Expand All @@ -15,7 +15,7 @@ pub struct Vm<A: Alloc> {
stack: Vec<Value<A>, A>,
frames: Vec<CallFrame<A>, A>,
strings: StringPool<A>,
globals: HashMap<u32, Value<A>>,
globals: HashMap<Gc<str>, Value<A>>,
alloc: A,
}

Expand Down Expand Up @@ -47,11 +47,11 @@ impl<A: Alloc> Vm<A> {
self.run()
}

fn print_stack(&self, strings: &StringPool<A>) {
fn print_stack(&self) {
let mut buf = String::from(" ");
for val in &self.stack {
buf.push_str("[ ");
val.write(&mut buf, strings).unwrap();
val.write(&mut buf).unwrap();
buf.push_str(" ]");
}

Expand Down Expand Up @@ -138,12 +138,9 @@ impl<A: Alloc> Vm<A> {

while let Some(instr) = self.read_instr() {
if log_enabled!(Level::Trace) {
self.print_stack(&self.strings);
self.print_stack();
let f = frame!(self);
f.closure
.function
.chunk
.disassemble_instr(f.ip - 1, &self.strings);
f.closure.function.chunk.disassemble_instr(f.ip - 1);
}

match instr {
Expand Down Expand Up @@ -173,7 +170,7 @@ impl<A: Alloc> Vm<A> {
if let Some(value) = self.globals.get(&name) {
push!(self, value.clone());
} else {
runtime_error!(self, "Undefined variable {}", self.strings.lookup(name));
runtime_error!(self, "Undefined variable {}", name.as_ref());
}
}
SetGlobal => {
Expand All @@ -183,7 +180,7 @@ impl<A: Alloc> Vm<A> {
let value = peek!(self).clone();
self.globals.insert(name, value);
} else {
runtime_error!(self, "Undefined variable {}", self.strings.lookup(name));
runtime_error!(self, "Undefined variable {}", name.as_ref());
}
}
DefineGlobal => {
Expand All @@ -204,9 +201,7 @@ impl<A: Alloc> Vm<A> {
if let (Some(a), Some(b)) = (a.as_double(), b.as_double()) {
push!(self, Value::from(a + b));
} else if let (Some(sa), Some(sb)) = (a.as_string(), b.as_string()) {
let sa = self.strings.lookup(sa);
let sb = self.strings.lookup(sb);
let out = sa.to_string() + sb;
let out = sa.as_ref().to_string() + sb.as_ref();
let out = Object::new_string(&out, &mut self.strings);
push!(self, out.into());
} else {
Expand All @@ -233,7 +228,7 @@ impl<A: Alloc> Vm<A> {
}
Print => {
let mut s = String::new();
pop!(self).write(&mut s, &self.strings).unwrap();
pop!(self).write(&mut s).unwrap();
println!("{}", s);
}
Jump => {
Expand Down

0 comments on commit acf621b

Please sign in to comment.