Fixes for uninitialised garbage collected pointers, jumps and identifiers in the compiler. Built but erroring on eq.
This commit is contained in:
parent
d2f47604bf
commit
44b389a6a1
5 changed files with 2922 additions and 2640 deletions
BIN
mars-49d70575ae6f08.core
Normal file
BIN
mars-49d70575ae6f08.core
Normal file
Binary file not shown.
65
src/gc.rs
65
src/gc.rs
|
|
@ -1,4 +1,4 @@
|
||||||
use std::alloc::{alloc, dealloc, Layout};
|
use std::alloc::{Layout, alloc, dealloc};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
@ -24,7 +24,7 @@ in the allocator ensure location is consistent
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Gc<T: ?Sized + Traverse> {
|
pub struct Gc<T: ?Sized + Traverse> {
|
||||||
it: NonNull<RefCell<Header<T>>>
|
it: NonNull<RefCell<Header<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Agc {}
|
pub struct Agc {}
|
||||||
|
|
@ -48,18 +48,25 @@ impl<T: ?Sized + Traverse> PartialEq for Gc<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized + Traverse> Gc<T> {
|
impl<T: ?Sized + Traverse> Gc<T> {
|
||||||
pub fn borrow(&self) -> impl Deref<Target=T> {
|
pub fn borrow(&self) -> impl Deref<Target = T> {
|
||||||
Ref::map(unsafe { // ???
|
Ref::map(
|
||||||
|
unsafe {
|
||||||
|
// ???
|
||||||
(*self.it.as_ptr()).borrow()
|
(*self.it.as_ptr()).borrow()
|
||||||
},|it| &it.data)
|
},
|
||||||
|
|it| &it.data,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
pub fn borrow_mut(&mut self) -> impl DerefMut<Target=T> {
|
pub fn borrow_mut(&mut self) -> impl DerefMut<Target = T> {
|
||||||
RefMut::map(unsafe {
|
RefMut::map(unsafe { (*self.it.as_mut()).borrow_mut() }, |it| {
|
||||||
(*self.it.as_mut()).borrow_mut()
|
&mut it.data
|
||||||
},|it| &mut it.data)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace(&mut self, new: T) where T: Sized {
|
pub fn replace(&mut self, new: T)
|
||||||
|
where
|
||||||
|
T: Sized,
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.it.as_mut()).borrow_mut().data = new;
|
(*self.it.as_mut()).borrow_mut().data = new;
|
||||||
}
|
}
|
||||||
|
|
@ -79,13 +86,13 @@ enum Color {
|
||||||
struct Header<T: ?Sized + Traverse> {
|
struct Header<T: ?Sized + Traverse> {
|
||||||
layout: Layout,
|
layout: Layout,
|
||||||
color: Color, // NOT for incremental tri-color right now; white == mark-free, black == mark-keep
|
color: Color, // NOT for incremental tri-color right now; white == mark-free, black == mark-keep
|
||||||
data: T
|
data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Allocator {
|
pub struct Allocator {
|
||||||
// An array of pointers is used here since I did not want to use a compactor and larger types
|
// An array of pointers is used here since I did not want to use a compactor and larger types
|
||||||
// held on the GC (game objects) will most likely be massive anyway.
|
// held on the GC (game objects) will most likely be massive anyway.
|
||||||
objects: Vec<Option<*mut RefCell<Header<dyn Traverse>>>>,
|
objects: Vec<Option<NonNull<RefCell<Header<dyn Traverse>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocator {
|
impl Allocator {
|
||||||
|
|
@ -94,15 +101,19 @@ impl Allocator {
|
||||||
objects: Vec::new(),
|
objects: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn alloc<T: Traverse + 'static>(&mut self, it: T) -> Gc<T> {
|
pub fn alloc<T: Traverse>(&mut self, it: T) -> Gc<T> {
|
||||||
let layout = Layout::new::<RefCell<Header<T>>>();
|
let layout = Layout::new::<RefCell<Header<T>>>();
|
||||||
let pointer = unsafe { alloc(layout) as *mut RefCell<Header<T>> }; // todo: maybe use a compacting GC
|
let pointer = unsafe {
|
||||||
assert!(!pointer.is_null()); // lol idk how to fix this rn
|
let pointer = alloc(layout) as *mut RefCell<Header<T>>;
|
||||||
let mut header = unsafe { pointer.as_mut() }.unwrap().borrow_mut();
|
assert!(!pointer.is_null()); // lol idk how to fix this rn (gah use a result!!!)
|
||||||
header.layout = layout;
|
pointer.write(RefCell::new(Header {
|
||||||
header.color = Color::Black;
|
layout,
|
||||||
header.data = it;
|
color: Color::Black,
|
||||||
self.objects.push(Some(pointer as *mut RefCell<Header<dyn Traverse>>));
|
data: it,
|
||||||
|
}));
|
||||||
|
pointer
|
||||||
|
}; // todo: maybe use a compacting GC
|
||||||
|
self.objects.push(NonNull::new(pointer));
|
||||||
Gc {
|
Gc {
|
||||||
it: NonNull::new(pointer).unwrap(),
|
it: NonNull::new(pointer).unwrap(),
|
||||||
}
|
}
|
||||||
|
|
@ -110,20 +121,23 @@ impl Allocator {
|
||||||
fn mark_white(&mut self) {
|
fn mark_white(&mut self) {
|
||||||
for i in 0..self.objects.len() {
|
for i in 0..self.objects.len() {
|
||||||
if let Some(object) = self.objects[i] {
|
if let Some(object) = self.objects[i] {
|
||||||
unsafe { (*object).borrow_mut().color = Color::White };
|
unsafe { (*object.as_ptr()).borrow_mut().color = Color::White };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn collect(&mut self) {
|
fn collect(&mut self) {
|
||||||
|
self.mark_white();
|
||||||
self.objects.retain(|object| {
|
self.objects.retain(|object| {
|
||||||
if let Some(object) = object {
|
if let Some(object) = object {
|
||||||
let header = unsafe { (**object).borrow_mut() };
|
let header = unsafe { (*object.as_ptr()).borrow_mut() };
|
||||||
match header.color {
|
match header.color {
|
||||||
Color::White => {
|
Color::White => {
|
||||||
unsafe { dealloc(*object as *mut u8,header.layout); }
|
unsafe {
|
||||||
|
dealloc(object.as_ptr() as *mut u8, header.layout);
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Color::Black => false
|
Color::Black => false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|
@ -133,7 +147,8 @@ impl Allocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Traverse: Any + Debug {
|
pub trait Traverse: Any + Debug {
|
||||||
fn traverse(&self) { // mark or grey
|
fn traverse(&self) {
|
||||||
|
// mark or grey
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1114
src/lib.rs
1114
src/lib.rs
File diff suppressed because it is too large
Load diff
111
src/table.rs
111
src/table.rs
|
|
@ -1,7 +1,6 @@
|
||||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
|
||||||
use std::rc::Rc;
|
|
||||||
use crate::gc::{Gc, Traverse};
|
use crate::gc::{Gc, Traverse};
|
||||||
use crate::{Callable, RunError, Value};
|
use crate::{Callable, RunError, Value};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
// I've already spent 2 months on this interpreter, and I'm tired, so I've cut a few corners...
|
// I've already spent 2 months on this interpreter, and I'm tired, so I've cut a few corners...
|
||||||
/* See some of Lua's notes on this table: https://www.lua.org/source/5.5/ltable.c.html
|
/* See some of Lua's notes on this table: https://www.lua.org/source/5.5/ltable.c.html
|
||||||
|
|
@ -25,6 +24,7 @@ Notes:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type Displacement = u8;
|
type Displacement = u8;
|
||||||
|
pub type Hashed = usize;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Entry {
|
struct Entry {
|
||||||
|
|
@ -45,31 +45,22 @@ impl Default for Entry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash(value: &Value) -> usize {
|
pub fn hash(value: &Value) -> Hashed {
|
||||||
match value {
|
match value {
|
||||||
Value::Nil => { 0 }
|
Value::Nil => 0,
|
||||||
Value::Bool(boolean) => { if *boolean { 1 } else { 0 } }
|
Value::Bool(boolean) => {
|
||||||
Value::String(string) => {
|
if *boolean {
|
||||||
let mut hasher = DefaultHasher::new();
|
1
|
||||||
string.hash(&mut hasher);
|
} else {
|
||||||
hasher.finish() as usize
|
0
|
||||||
}
|
|
||||||
Value::Phrase(phrase) => {
|
|
||||||
phrase.1
|
|
||||||
}
|
|
||||||
Value::Function(callable) => {
|
|
||||||
match callable {
|
|
||||||
Callable::Rust(native) => {
|
|
||||||
Rc::as_ptr(native).addr()
|
|
||||||
}
|
|
||||||
Callable::Mars(closure) => {
|
|
||||||
closure.addr()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Value::String(_string, hash) => *hash,
|
||||||
Value::Integer(integer) => {
|
Value::Function(callable) => match callable {
|
||||||
*integer as usize
|
Callable::Rust(native) => Rc::as_ptr(native).addr(),
|
||||||
}
|
Callable::Mars(closure) => closure.addr(),
|
||||||
|
},
|
||||||
|
Value::Integer(integer) => *integer as usize,
|
||||||
Value::Number(number) => {
|
Value::Number(number) => {
|
||||||
if number.is_nan() {
|
if number.is_nan() {
|
||||||
0
|
0
|
||||||
|
|
@ -77,12 +68,8 @@ pub fn hash(value: &Value) -> usize {
|
||||||
number.to_bits() as usize
|
number.to_bits() as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Table(table) => {
|
Value::Table(table) => table.addr(),
|
||||||
table.addr()
|
Value::Object(object) => object.addr(),
|
||||||
}
|
|
||||||
Value::Object(object) => {
|
|
||||||
object.addr()
|
|
||||||
}
|
|
||||||
#[cfg(feature = "vector3")]
|
#[cfg(feature = "vector3")]
|
||||||
Value::Vector(vec) => {
|
Value::Vector(vec) => {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
|
|
@ -99,13 +86,13 @@ pub struct Table {
|
||||||
array: Vec<Value>,
|
array: Vec<Value>,
|
||||||
table_bounds: std::ops::Range<usize>,
|
table_bounds: std::ops::Range<usize>,
|
||||||
table_count: usize, // number of elements in table
|
table_count: usize, // number of elements in table
|
||||||
pub meta: Option<Gc<Table>>
|
pub meta: Option<Gc<Table>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Traverse for Table {
|
impl Traverse for Table {
|
||||||
fn traverse(&self) {
|
fn traverse(&self) {
|
||||||
for Entry { index, item, .. } in self.table.iter() {
|
for Entry { index, item, .. } in self.table.iter() {
|
||||||
if !matches!(index,Value::Nil) {
|
if !matches!(index, Value::Nil) {
|
||||||
index.traverse();
|
index.traverse();
|
||||||
item.traverse();
|
item.traverse();
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +108,7 @@ impl Table {
|
||||||
let old = std::mem::replace(&mut self.table, vec![Entry::default(); len]);
|
let old = std::mem::replace(&mut self.table, vec![Entry::default(); len]);
|
||||||
for Entry { index, item, .. } in old {
|
for Entry { index, item, .. } in old {
|
||||||
if index != Value::Nil {
|
if index != Value::Nil {
|
||||||
self.set_table(index,item)
|
self.set_table(index, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +117,7 @@ impl Table {
|
||||||
self.table_bounds = 0..self.table_upper();
|
self.table_bounds = 0..self.table_upper();
|
||||||
}
|
}
|
||||||
pub fn resize_array(&mut self, len: usize) {
|
pub fn resize_array(&mut self, len: usize) {
|
||||||
self.array.resize(len,Value::Nil)
|
self.array.resize(len, Value::Nil)
|
||||||
}
|
}
|
||||||
fn table_upper(&self) -> usize {
|
fn table_upper(&self) -> usize {
|
||||||
(self.table.len() / 4) * 3
|
(self.table.len() / 4) * 3
|
||||||
|
|
@ -139,38 +126,44 @@ impl Table {
|
||||||
self.table.len() / 3
|
self.table.len() / 3
|
||||||
}
|
}
|
||||||
fn ensure_table(&mut self) {
|
fn ensure_table(&mut self) {
|
||||||
if self.table_count > self.table_upper() { // free space is short
|
if self.table_count > self.table_upper() {
|
||||||
|
// free space is short
|
||||||
self.exchange_table((self.table.len() + 4) * 2);
|
self.exchange_table((self.table.len() + 4) * 2);
|
||||||
} else if self.table_count < self.table_lower() { // too much free space
|
} else if self.table_count < self.table_lower() {
|
||||||
|
// too much free space
|
||||||
self.exchange_table(self.table.len() / 2)
|
self.exchange_table(self.table.len() / 2)
|
||||||
}
|
}
|
||||||
self.table_bounds = self.table_lower()..self.table_upper()
|
self.table_bounds = self.table_lower()..self.table_upper()
|
||||||
}
|
}
|
||||||
fn set_table(&mut self, index: Value, item: Value) {
|
fn set_table(&mut self, index: Value, item: Value) {
|
||||||
#[cfg(feature = "assertions")]
|
#[cfg(feature = "assertions")]
|
||||||
assert_ne!(index,Value::Nil);
|
assert_ne!(index, Value::Nil);
|
||||||
#[cfg(feature = "assertions")]
|
#[cfg(feature = "assertions")]
|
||||||
assert_ne!(item,Value::Nil);
|
assert_ne!(item, Value::Nil);
|
||||||
if !self.table_bounds.contains(&self.table_count) { // make sure the table is appropriately sized
|
if !self.table_bounds.contains(&self.table_count) {
|
||||||
|
// make sure the table is appropriately sized
|
||||||
self.ensure_table();
|
self.ensure_table();
|
||||||
}
|
}
|
||||||
let range = self.table.len();
|
let range = self.table.len();
|
||||||
let home = hash(&index) % range;
|
let home = hash(&index) % range;
|
||||||
if self.table[home].index == Value::Nil { // attempt to place it directly in an empty space
|
if self.table[home].index == Value::Nil {
|
||||||
|
// attempt to place it directly in an empty space
|
||||||
// INSERT
|
// INSERT
|
||||||
self.table[home].home = home;
|
self.table[home].home = home;
|
||||||
self.table[home].item = item; // home.item.soft_drop()
|
self.table[home].item = item; // home.item.soft_drop()
|
||||||
self.table[home].index = index;
|
self.table[home].index = index;
|
||||||
self.table[home].displacement = self.table[home].displacement.max(0);
|
self.table[home].displacement = self.table[home].displacement.max(0);
|
||||||
self.table_count += 1;
|
self.table_count += 1;
|
||||||
} else if self.table[home].index == index { // attempt to replace it directly
|
} else if self.table[home].index == index {
|
||||||
|
// attempt to replace it directly
|
||||||
// REPLACE
|
// REPLACE
|
||||||
self.table[home].item = item; // home.item.soft_drop()
|
self.table[home].item = item; // home.item.soft_drop()
|
||||||
} else {
|
} else {
|
||||||
// attempt to replace it in a collided neighbour location
|
// attempt to replace it in a collided neighbour location
|
||||||
for i in 1..self.table[home].displacement + 1 {
|
for i in 1..self.table[home].displacement + 1 {
|
||||||
let neighbour = &mut self.table[(home + i as usize) % range]; // todo: is mod expensive?
|
let neighbour = &mut self.table[(home + i as usize) % range]; // todo: is mod expensive?
|
||||||
if neighbour.index == index { // found where it was displaced to
|
if neighbour.index == index {
|
||||||
|
// found where it was displaced to
|
||||||
// REPLACE
|
// REPLACE
|
||||||
neighbour.item = item;
|
neighbour.item = item;
|
||||||
return;
|
return;
|
||||||
|
|
@ -179,7 +172,8 @@ impl Table {
|
||||||
// at this point it must be added, probe to place in an empty space
|
// at this point it must be added, probe to place in an empty space
|
||||||
for j in self.table[home].displacement + 1..Displacement::MAX - 1 {
|
for j in self.table[home].displacement + 1..Displacement::MAX - 1 {
|
||||||
let neighbour = &mut self.table[(home + j as usize) % range];
|
let neighbour = &mut self.table[(home + j as usize) % range];
|
||||||
if neighbour.index == Value::Nil { // new empty slot hooray!
|
if neighbour.index == Value::Nil {
|
||||||
|
// new empty slot hooray!
|
||||||
// INSERT
|
// INSERT
|
||||||
neighbour.home = home;
|
neighbour.home = home;
|
||||||
neighbour.item = item;
|
neighbour.item = item;
|
||||||
|
|
@ -216,7 +210,7 @@ impl Table {
|
||||||
#[cfg(feature = "messages")]
|
#[cfg(feature = "messages")]
|
||||||
eprintln!("\n\tResizing...");
|
eprintln!("\n\tResizing...");
|
||||||
self.resize_table((self.table.len() + 4) * 2);
|
self.resize_table((self.table.len() + 4) * 2);
|
||||||
self.set_table(index,item);
|
self.set_table(index, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn rem_table(&mut self, index: Value) {
|
fn rem_table(&mut self, index: Value) {
|
||||||
|
|
@ -272,9 +266,10 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set(&mut self, index: Value, item: Value) -> Result<(),RunError> {
|
pub fn set(&mut self, index: Value, item: Value) -> Result<(), RunError> {
|
||||||
match index {
|
match index {
|
||||||
Value::Integer(index) => { // This is an integer index, try the array first
|
Value::Integer(index) => {
|
||||||
|
// This is an integer index, try the array first
|
||||||
match item {
|
match item {
|
||||||
Value::Nil => {
|
Value::Nil => {
|
||||||
if (0..self.array.len() + 1).contains(&(index as usize)) {
|
if (0..self.array.len() + 1).contains(&(index as usize)) {
|
||||||
|
|
@ -285,7 +280,7 @@ impl Table {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.rem_table(Value::Integer(index));
|
self.rem_table(Value::Integer(index));
|
||||||
},
|
}
|
||||||
item => {
|
item => {
|
||||||
if (0..self.array.len() + 1).contains(&(index as usize)) {
|
if (0..self.array.len() + 1).contains(&(index as usize)) {
|
||||||
if self.array.len() == index as usize {
|
if self.array.len() == index as usize {
|
||||||
|
|
@ -294,19 +289,25 @@ impl Table {
|
||||||
self.array[index as usize + 1] = item;
|
self.array[index as usize + 1] = item;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.set_table(Value::Integer(index),item)
|
self.set_table(Value::Integer(index), item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
}
|
||||||
Value::Nil => Err(RunError("Attempt to set new index of tabel with key: nil".to_string())),
|
Value::Nil => Err(RunError(
|
||||||
index => Ok(self.set_table(index,item))
|
"Attempt to set new index of tabel with key: nil".to_string(),
|
||||||
|
)),
|
||||||
|
index => Ok(self.set_table(index, item)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get(&self, index: Value) -> Result<Value,RunError> {
|
pub fn get(&self, index: Value) -> Result<Value, RunError> {
|
||||||
match index {
|
match index {
|
||||||
Value::Integer(index) => Ok(self.array.get(index as usize).unwrap_or(&Value::Nil).clone()),
|
Value::Integer(index) => Ok(self
|
||||||
|
.array
|
||||||
|
.get(index as usize)
|
||||||
|
.unwrap_or(&Value::Nil)
|
||||||
|
.clone()),
|
||||||
Value::Nil => Err(RunError("Attempt to index table with key: nil".to_string())),
|
Value::Nil => Err(RunError("Attempt to index table with key: nil".to_string())),
|
||||||
index => {
|
index => {
|
||||||
let location = hash(&index) % self.table.len();
|
let location = hash(&index) % self.table.len();
|
||||||
|
|
@ -317,7 +318,7 @@ impl Table {
|
||||||
for i in 1..home.displacement as usize {
|
for i in 1..home.displacement as usize {
|
||||||
let neighbour = &self.table[location + i];
|
let neighbour = &self.table[location + i];
|
||||||
if neighbour.index == index {
|
if neighbour.index == index {
|
||||||
return Ok(neighbour.item.clone())
|
return Ok(neighbour.item.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Value::Nil)
|
Ok(Value::Nil)
|
||||||
|
|
@ -334,7 +335,7 @@ impl Table {
|
||||||
array: Vec::new(),
|
array: Vec::new(),
|
||||||
table_count: 0,
|
table_count: 0,
|
||||||
table_bounds: (0..0).into(),
|
table_bounds: (0..0).into(),
|
||||||
meta: None
|
meta: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1 +1,5 @@
|
||||||
do end
|
if true then
|
||||||
|
print("whats good")
|
||||||
|
else
|
||||||
|
print("oh no")
|
||||||
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue