Skip to content

Commit

Permalink
Merge pull request #4 from notJoon:gc
Browse files Browse the repository at this point in the history
Gc
  • Loading branch information
notJoon authored Nov 27, 2023
2 parents c8cb68e + 39a5918 commit 45eb6b4
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 43 deletions.
16 changes: 13 additions & 3 deletions src/alloc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use std::fmt::Debug;

use crate::{object::{ObjectAddress, Object}, heap::Heap, free_list::{self, FreeList}, mem::{Memory, Status}};
use crate::object::ObjectTrait;
use crate::{
free_list::FreeList,
heap::Heap,
mem::{Memory, Status},
object::{Object, ObjectAddress},
};

#[derive(Debug, Default)]
pub struct Allocator {}
Expand All @@ -15,7 +20,12 @@ impl Allocator {
Default::default()
}

pub fn allocate(&mut self, heap: &mut Heap, object: Object, is_root: bool) -> Result<ObjectAddress, AllocatorError> {
pub fn allocate(
&mut self,
heap: &mut Heap,
object: Object,
is_root: bool,
) -> Result<ObjectAddress, AllocatorError> {
let size = object.size();

if let Some(alignment_start) = self.find_free_block(heap, size) {
Expand Down Expand Up @@ -83,4 +93,4 @@ pub fn create_free_list_heap(alignment: usize, free_list: Vec<(ObjectAddress, us
alignment,
..Default::default()
}
}
}
62 changes: 55 additions & 7 deletions src/gc.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,59 @@
use std::fmt;

use crate::{controller::PIController, vm::{VirtualMachine, OpCode}, heap::{Heap, self}, object::{ObjectAddress, ObjectTrait, Object, Field, Address}};
use crate::{
controller::{PIConfig, PIController},
object::{ObjectAddress, ObjectTrait},
vm::{OpCode, VirtualMachine},
};

pub struct TriColorGC {
pub color: TriColor,
}

#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Default)]
pub enum GCType {
#[default]
MarkAndSweep,
}

#[derive(Debug, PartialEq, Clone, Copy)]
#[derive(Debug, PartialEq, Default, Clone)]
pub enum GCStatus {
#[default]
Idle,
Marking,
Sweeping,
}

#[derive(Debug, PartialEq, Clone, Copy, Default)]
pub enum TriColor {
#[default]
White,
Gray,
Black,
}

#[derive(Debug, PartialEq, Clone)]
pub struct GarbageCollector {
pub gc_typ: GCType,
pub gc_status: GCStatus,
pub confidence: f64,
pub pi_controller: PIController,
}

impl GarbageCollector {
pub fn initialize_colors(&mut self, vm: &mut VirtualMachine) {
vm.heap.objects.values_mut().for_each(|o| {
o.header.marked = TriColor::White;
})
}

pub fn update_color(&self, addr: ObjectAddress, new_color: TriColor, vm: &mut VirtualMachine) {
if let Some(obj) = vm.heap.objects.get_mut(&addr) {
obj.header.marked = new_color;
}
}
}

pub trait Marker {
fn mark_from_roots(&self, vm: &mut VirtualMachine) -> Option<bool> {
vm.init_object();
Expand All @@ -32,6 +68,10 @@ pub trait Marker {

while let Some(curr_addr) = grays.pop() {
if vm.process_object(curr_addr, &mut grays) {
vm.op_codes.push(OpCode::Mark(
curr_addr,
vm.heap.objects.get(&curr_addr).unwrap().size(),
));
continue;
}
}
Expand All @@ -44,6 +84,7 @@ pub trait Marker {
for (addr, obj) in vm.heap.objects.iter_mut() {
if obj.header.marked == TriColor::Black {
obj.header.marked = TriColor::White;
vm.op_codes.push(OpCode::Sweep);
sweeped += 1;
} else {
freed += 1;
Expand All @@ -55,6 +96,17 @@ pub trait Marker {
}
}

impl Default for GarbageCollector {
fn default() -> Self {
Self {
gc_typ: GCType::MarkAndSweep,
gc_status: GCStatus::Idle,
confidence: 0.0,
pi_controller: PIController::new(PIConfig::default()),
}
}
}

impl fmt::Display for TriColor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expand All @@ -64,7 +116,3 @@ impl fmt::Display for TriColor {
}
}
}

pub struct MarkAndSweep {
pub pi: PIController,
}
38 changes: 37 additions & 1 deletion src/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
use crate::{
free_list::FreeList,
mem::{self, Memory},
object::{Address, Field, Object, ObjectAddress, ObjectTrait},
object::{Address, Field, Object, ObjectAddress, ObjectTrait, ObjectHeader},
};

#[derive(Debug, PartialEq, Clone, Default)]
Expand Down Expand Up @@ -37,6 +37,42 @@ impl Heap {
}
}

pub fn allocate_object(&mut self, size: usize) -> Result<ObjectAddress, HeapError> {
let aligned_size = self.aligned_position(size);
let address = self.find_free_block(aligned_size)?;

let new_object = Object {
header: ObjectHeader {
size: aligned_size,
..Default::default()
},
..Default::default()
};

// add object to the heap
self.objects.insert(address, new_object.to_owned());
self.free_list.remove(address);
self.update_memory_status(address, aligned_size, mem::Status::Allocated);

Ok(address)
}

fn find_free_block(&self, size: usize) -> Result<ObjectAddress, HeapError> {
self.free_list
.iter()
.find(|(_, len)| *len >= &size)
.map(|(addr, _)| *addr)
.ok_or(HeapError::OutOfMemory)
}

fn update_memory_status(&mut self, start: usize, size: usize, status: mem::Status) {
for offset in 0..size {
if let Some(cell) = self.memory.get_mut(start + offset) {
cell.status = status.to_owned();
}
}
}

/// Find `Object` in the heap based on the given address.
pub fn lookup(&self, address: usize) -> Result<ObjectAddress, HeapError> {
if let Some((_addr, obj)) = self.objects.iter().find(|(_, obj)| {
Expand Down
27 changes: 14 additions & 13 deletions src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct Object {
pub fields: Vec<Field>,
}

#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Default)]
pub struct ObjectHeader {
pub size: usize,
pub next: Option<Address>,
Expand Down Expand Up @@ -65,7 +65,6 @@ pub trait ObjectTrait {
fn is_marked(&self) -> bool;
fn size(&self) -> usize;
fn create_random_object(name: Option<&str>) -> Self;
fn to_string(&self) -> String;
fn inject_address(&mut self, addr: ObjectAddress);
}

Expand Down Expand Up @@ -140,17 +139,6 @@ impl ObjectTrait for Object {
}
}

fn to_string(&self) -> String {
let mut s = String::new();
s.push_str(&format!("Object: {}\n", self.ident));
s.push_str(&format!("Address: {:?}\n", self.addr));
s.push_str(&format!("Size: {} bytes\n", self.size()));
s.push_str(&format!("Marked: {:?}\n", self.header.marked));
s.push_str(&format!("References: {:?}\n", self.references));
s.push_str(&format!("Fields: {:?}\n", self.fields));
s
}

// testing purpose
fn inject_address(&mut self, addr: ObjectAddress) {
self.addr = addr;
Expand Down Expand Up @@ -208,3 +196,16 @@ impl fmt::Display for TypeValue {
}
}
}

impl fmt::Display for Object {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = String::new();
s.push_str(&format!("Object: {}\n", self.ident));
s.push_str(&format!("Address: {:?}\n", self.addr));
s.push_str(&format!("Size: {} bytes\n", self.size()));
s.push_str(&format!("Marked: {:?}\n", self.header.marked));
s.push_str(&format!("References: {:?}\n", self.references));
s.push_str(&format!("Fields: {:?}\n", self.fields));
write!(f, "{}", s)
}
}
30 changes: 13 additions & 17 deletions src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
use core::fmt;

use crate::{object::{Object, TypeValue, ObjectAddress, ObjectTrait, Address, Field}, heap::Heap, gc::TriColor};

#[derive(Debug, PartialEq, Default, Clone)]
pub enum GCStatus {
#[default]
Idle,
Marking,
Sweeping,
}
use crate::{
gc::{GCStatus, GCType, GarbageCollector, TriColor},
heap::Heap,
object::{Address, Field, Object, ObjectAddress, ObjectTrait, TypeValue},
};

#[derive(Debug, PartialEq, Clone)]
pub enum VMError {
Expand Down Expand Up @@ -40,13 +36,16 @@ pub struct VirtualMachine {
pub num_objects: usize,
pub first_object: Option<Object>,

pub gc_confidence: f64,
pub trigger_gc: bool,
pub gc_status: GCStatus,
pub gc: GarbageCollector,
}

impl VirtualMachine {
pub fn new(max_stack_size: usize, threshold: f64, heap_size: usize, alignment: usize) -> Result<Self, VMError> {
pub fn new(
max_stack_size: usize,
threshold: f64,
heap_size: usize,
alignment: usize,
) -> Result<Self, VMError> {
if threshold <= 0.0 || threshold >= 100.0 {
return Err(VMError::InvalidRangeOfThreshold);
}
Expand Down Expand Up @@ -188,16 +187,13 @@ impl fmt::Display for VirtualMachine {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VM: {{\nstack: {:?},\nop_codes: {:?},\nmax_stack_size: {},\nthreshold: {},\nnum_objects: {},\nfirst_object: {:?},\ngc_confidence: {},\ntrigger_gc: {},\ngc_status: {}\n}}",
"VM: {{\nstack: {:?},\nop_codes: {:?},\nmax_stack_size: {},\nthreshold: {},\nnum_objects: {},\nfirst_object: {:?}\n}}",
self.stack,
self.op_codes,
self.max_stack_size,
self.threshold,
self.num_objects,
self.first_object,
self.gc_confidence,
self.trigger_gc,
self.gc_status
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/alloc_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ mod alloc_tests {
assert_eq!(result, Some(1));
assert_eq!(heap.free_list.to_vec(), vec![(1, 1)]);
}
}
}
41 changes: 41 additions & 0 deletions tests/gc_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#[cfg(test)]
mod marker_tests {
use gc_simulator::{vm::VirtualMachine, gc::{GarbageCollector, TriColor}, object::{Object, ObjectTrait, TypeValue}};

fn vm_setup() -> VirtualMachine {
VirtualMachine::new(10, 0.5, 100, 8).unwrap()
}

fn gc_setup() -> GarbageCollector {
GarbageCollector::default()
}

#[test]
fn test_initialization_of_objects() {
let mut vm = vm_setup();
let mut gc = gc_setup();

assert_eq!(vm.heap.objects.values().all(|o| o.header.marked == TriColor::White), true);

gc.initialize_colors(&mut vm);

assert!(vm.heap.objects.values().all(|o| o.header.marked == TriColor::White));
}

#[test]
fn test_update_color() {
let mut vm = vm_setup();
let gc = gc_setup();

let obj1 = Object::new("obj1".to_string(), TypeValue::Int(42));
let obj2 = Object::new("obj2".to_string(), TypeValue::Int(42));

vm.push(obj1).unwrap();
vm.push(obj2).unwrap();

let obj1_addr = vm.stack[0].get_address();
gc.update_color(obj1_addr, TriColor::Gray, &mut vm);

assert_eq!(vm.stack[0].header.marked, TriColor::Gray);
}
}
22 changes: 21 additions & 1 deletion tests/heap_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
mod heap_tests {
use gc_simulator::{
heap::Heap,
object::{Object, ObjectTrait},
object::{Object, ObjectTrait}, gc::TriColor,
};

#[test]
Expand Down Expand Up @@ -112,4 +112,24 @@ mod heap_tests {
assert_eq!(h.aligned_position(i), i);
}
}

#[test]
fn test_initialization_heap_color() {
let mut heap = Heap::new(1024, 0);
let addr1 = heap.allocate_object(64).unwrap();
let addr2 = heap.allocate_object(64).unwrap();

assert_eq!(heap.objects.get(&addr1).unwrap().header.marked, TriColor::White);
assert_eq!(heap.objects.get(&addr2).unwrap().header.marked, TriColor::White);

heap.objects.get_mut(&addr1).unwrap().header.marked = TriColor::Gray;
heap.objects.get_mut(&addr2).unwrap().header.marked = TriColor::Gray;

for obj in heap.objects.values() {
assert_eq!(obj.header.marked, TriColor::Gray);
}

assert_eq!(heap.objects.get(&addr1).unwrap().header.marked, TriColor::Gray);
assert_eq!(heap.objects.get(&addr2).unwrap().header.marked, TriColor::Gray);
}
}
Loading

0 comments on commit 45eb6b4

Please sign in to comment.