Experimenting with garbage collection algorithm.
This commit is contained in:
		
							parent
							
								
									34fae6ccca
								
							
						
					
					
						commit
						d09d945323
					
				
							
								
								
									
										205
									
								
								src/vm/mem/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								src/vm/mem/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,205 @@ | |||||||
|  | use std::cell::RefCell; | ||||||
|  | use std::marker::PhantomData; | ||||||
|  | use std::ops::Mul; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Gc<T> { | ||||||
|  |     inner: *mut GcInner, | ||||||
|  |     data: *const T, | ||||||
|  |     _phantom: PhantomData<T>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[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<T> Gc<T> { | ||||||
|  |     pub fn new(data: T) -> Self { | ||||||
|  |         let inner = Box::into_raw(Box::new(GcInner::new(size_of::<T>()))); | ||||||
|  |         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<T> Clone for Gc<T> { | ||||||
|  |     fn clone(&self) -> Self { | ||||||
|  |         Self { | ||||||
|  |             inner: self.inner, | ||||||
|  |             data: self.data, | ||||||
|  |             _phantom: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | enum DvmValue { | ||||||
|  |     Primitive(usize), | ||||||
|  |     Object(Gc<RefCell<DvmObject>>), | ||||||
|  |     Nil, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct DvmObject { | ||||||
|  |     fields: Vec<DvmValue>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl DvmObject { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self { fields: vec![] } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn fields(&self) -> &[DvmValue] { | ||||||
|  |         &self.fields | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn fields_mut(&mut self) -> &mut Vec<DvmValue> { | ||||||
|  |         &mut self.fields | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn collect_garbage( | ||||||
|  |     next_gc: &mut usize, | ||||||
|  |     current_size: &mut usize, | ||||||
|  |     stack: &Vec<DvmValue>, | ||||||
|  |     gcs: &mut Vec<Gc<RefCell<DvmObject>>>, | ||||||
|  | ) { | ||||||
|  |     let mut gray_stack: Vec<Gc<RefCell<DvmObject>>> = 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<DvmValue>, | ||||||
|  |     gcs: &mut Vec<Gc<RefCell<DvmObject>>>, | ||||||
|  | ) { | ||||||
|  |     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<DvmValue>, | ||||||
|  |     gcs: &mut Vec<Gc<RefCell<DvmObject>>>, | ||||||
|  | ) -> Gc<RefCell<DvmObject>> { | ||||||
|  |     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<RefCell<DvmObject>>, 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<DvmValue> = vec![]; | ||||||
|  |         let mut heap: Vec<Gc<RefCell<DvmObject>>> = 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); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -6,6 +6,7 @@ pub mod implementation; | |||||||
| pub mod instruction; | pub mod instruction; | ||||||
| pub mod interface; | pub mod interface; | ||||||
| pub mod lib; | pub mod lib; | ||||||
|  | mod mem; | ||||||
| pub mod method; | pub mod method; | ||||||
| pub mod object; | pub mod object; | ||||||
| pub mod op_codes; | pub mod op_codes; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Jesse Brault
						Jesse Brault