From d09d945323f0c36ab112bf88e0866c2be3528ef1 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Tue, 14 Oct 2025 21:18:06 -0500 Subject: [PATCH] Experimenting with garbage collection algorithm. --- src/vm/mem/mod.rs | 205 ++++++++++++++++++++++++++++++++++++++++++++++ src/vm/mod.rs | 1 + 2 files changed, 206 insertions(+) create mode 100644 src/vm/mem/mod.rs diff --git a/src/vm/mem/mod.rs b/src/vm/mem/mod.rs new file mode 100644 index 0000000..61fbf20 --- /dev/null +++ b/src/vm/mem/mod.rs @@ -0,0 +1,205 @@ +use std::cell::RefCell; +use std::marker::PhantomData; +use std::ops::Mul; + +#[derive(Debug)] +pub struct Gc { + inner: *mut GcInner, + data: *const T, + _phantom: PhantomData, +} + +#[derive(Debug)] +pub struct GcInner { + color: GcColor, + size: usize, +} + +impl GcInner { + pub fn new(size: usize) -> Self { + Self { + color: GcColor::White, + size, + } + } +} + +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum GcColor { + White, + Black, +} + +impl Gc { + pub fn new(data: T) -> Self { + let inner = Box::into_raw(Box::new(GcInner::new(size_of::()))); + let boxed_data = Box::into_raw(Box::new(data)) as *const T; + Self { + inner, + data: boxed_data, + _phantom: PhantomData, + } + } + + pub fn set_color(&mut self, color: GcColor) { + unsafe { + (*self.inner).color = color; + } + } + + pub fn color(&self) -> GcColor { + unsafe { (*self.inner).color } + } + + pub fn size(&self) -> usize { + unsafe { (*self.inner).size } + } + + pub fn data(&self) -> &T { + unsafe { &*self.data } + } + + pub fn dealloc(&mut self) { + unsafe { + drop(Box::from_raw(self.inner)); + drop(Box::from_raw(self.data as *mut T)); + } + } +} + +impl Clone for Gc { + fn clone(&self) -> Self { + Self { + inner: self.inner, + data: self.data, + _phantom: PhantomData, + } + } +} + +#[derive(Debug)] +enum DvmValue { + Primitive(usize), + Object(Gc>), + Nil, +} + +#[derive(Debug)] +struct DvmObject { + fields: Vec, +} + +impl DvmObject { + pub fn new() -> Self { + Self { fields: vec![] } + } + + pub fn fields(&self) -> &[DvmValue] { + &self.fields + } + + pub fn fields_mut(&mut self) -> &mut Vec { + &mut self.fields + } +} + +fn collect_garbage( + next_gc: &mut usize, + current_size: &mut usize, + stack: &Vec, + gcs: &mut Vec>>, +) { + let mut gray_stack: Vec>> = vec![]; + + for stack_value in stack { + match stack_value { + DvmValue::Object(gc) => { + if gc.color() == GcColor::White { + gray_stack.push(gc.clone()); + } + } + _ => {} + } + } + + while let Some(mut current) = gray_stack.pop() { + for field in current.data().borrow().fields() { + match field { + DvmValue::Object(object) => { + gray_stack.push(object.clone()); + } + _ => {} + } + } + current.set_color(GcColor::Black); + } + + let mut collected_size: usize = 0; + + for i in (0..gcs.len()).rev() { + if gcs[i].color() == GcColor::White { + let mut gc = gcs.remove(i); + let size = gc.size(); + *current_size -= size; + collected_size += size; + gc.dealloc(); + } else { + gcs[i].set_color(GcColor::White); + } + } + + *next_gc = std::cmp::max(1024 * 1024, current_size.mul(2)); + println!( + "collected_size: {}, current_size: {}, next_gc: {}", + collected_size, current_size, next_gc + ); +} + +fn maybe_collect_garbage( + next_gc: &mut usize, + current_size: &mut usize, + stack: &Vec, + gcs: &mut Vec>>, +) { + if current_size > next_gc { + collect_garbage(next_gc, current_size, stack, gcs); + } +} + +fn alloc_dvm_object( + next_gc: &mut usize, + current_size: &mut usize, + stack: &Vec, + gcs: &mut Vec>>, +) -> Gc> { + maybe_collect_garbage(next_gc, current_size, stack, gcs); + let mut object = DvmObject::new(); + object.fields_mut().push(DvmValue::Nil); + let gc = Gc::new(RefCell::new(object)); + *current_size += gc.size(); + gcs.push(gc.clone()); + gc +} + +fn set_field(obj: &mut Gc>, field_index: usize, value: DvmValue) { + let mut binding = obj.data().borrow_mut(); + binding.fields_mut()[field_index] = value; +} + +#[cfg(test)] +mod tests { + use crate::vm::mem::{alloc_dvm_object, collect_garbage, DvmObject, DvmValue, Gc}; + use std::cell::RefCell; + + #[test] + fn test() { + let mut stack: Vec = vec![]; + let mut heap: Vec>> = vec![]; + let mut next_gc: usize = 1024 * 1024; + let mut current_size: usize = 0; + for i in 0..100_000_000 { + let mut o = alloc_dvm_object(&mut next_gc, &mut current_size, &stack, &mut heap); + } + collect_garbage(&mut next_gc, &mut current_size, &stack, &mut heap); + } +} diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 3fa6b74..050abdb 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -6,6 +6,7 @@ pub mod implementation; pub mod instruction; pub mod interface; pub mod lib; +mod mem; pub mod method; pub mod object; pub mod op_codes;