Fixes for uninitialised garbage collected pointers, jumps and identifiers in the compiler. Built but erroring on eq.

This commit is contained in:
Christian Lincoln 2026-08-25 21:24:34 +01:00
parent d2f47604bf
commit 44b389a6a1
5 changed files with 2922 additions and 2640 deletions

BIN
mars-49d70575ae6f08.core Normal file

Binary file not shown.

View file

@ -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 {}
@ -49,17 +49,24 @@ 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
() ()
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -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,7 +86,7 @@ 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 {
@ -139,9 +126,11 @@ 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()
@ -151,26 +140,30 @@ impl Table {
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;
@ -274,7 +268,8 @@ 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 {
@ -299,14 +294,20 @@ impl Table {
} }
} }
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,
} }
} }
} }

View file

@ -1 +1,5 @@
do end if true then
print("whats good")
else
print("oh no")
end