From 520923a4b2e1dae5e8fb4243d674540393e96b1f Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Mon, 27 Nov 2023 11:25:22 +0900 Subject: [PATCH] refactor --- src/gc.rs | 6 --- src/heap.rs | 6 +-- src/main.rs | 5 +- src/mem.rs | 9 ++++ src/object.rs | 10 +++- src/vm.rs | 121 ++++++++++++++++----------------------------- tests/heap_test.rs | 14 +++--- tests/vm_test.rs | 38 +++++++++----- 8 files changed, 98 insertions(+), 111 deletions(-) diff --git a/src/gc.rs b/src/gc.rs index 134d885..116860e 100644 --- a/src/gc.rs +++ b/src/gc.rs @@ -39,9 +39,3 @@ impl fmt::Display for TriColor { pub struct MarkAndSweep { pub pi: PIController, } - -// impl GarbageCollector for MarkAndSweep { -// fn collect(&self, vm: &mut VM) { - -// } -// } diff --git a/src/heap.rs b/src/heap.rs index 15d8ef8..d5e99e8 100644 --- a/src/heap.rs +++ b/src/heap.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ free_list::FreeList, mem::{self, Memory}, - object::{Object, ObjectAddress, ObjectTrait, Field, Address}, + object::{Address, Field, Object, ObjectAddress, ObjectTrait}, }; #[derive(Debug, PartialEq, Clone)] @@ -119,9 +119,7 @@ impl Heap { /// Returns the address of the object that is next to the given address. pub fn next_object(&self, addr: usize) -> Option<&Object> { - self.objects - .values() - .find(|obj| obj.get_address() > addr) + self.objects.values().find(|obj| obj.get_address() > addr) } pub fn prev_object(&self, addr: usize) -> Option<&Object> { diff --git a/src/main.rs b/src/main.rs index e7a11a9..1096a30 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +use gc_simulator::vm::VirtualMachine; + fn main() { - println!("Hello, world!"); + let vm = VirtualMachine::new(1025, 10.5); + println!("{:?}", vm); } diff --git a/src/mem.rs b/src/mem.rs index 207d254..8332bf0 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -22,4 +22,13 @@ impl Memory { status: Status::Free, } } + + pub fn inspector(&self) -> String { + match self.status { + Status::Free => String::from("Free"), + Status::Allocated => String::from("Allocated"), + Status::Marked => String::from("Marked"), + Status::Used => String::from("Used"), + } + } } diff --git a/src/object.rs b/src/object.rs index e10dc85..6e8cb8b 100644 --- a/src/object.rs +++ b/src/object.rs @@ -9,6 +9,7 @@ use crate::gc::TriColor; pub type ObjectAddress = usize; +// Global counter for generating sequential UUIDs static COUNTER: AtomicUsize = AtomicUsize::new(0); #[derive(Debug, PartialEq, Clone)] @@ -189,11 +190,16 @@ impl default::Default for Object { #[allow(non_snake_case)] /// Generates a sequential UUID for simulating memory addresses. -/// +/// /// It is also possible to customize the address by using the `inject_address` method. fn generate_sequential_UUID() -> usize { let counter = COUNTER.fetch_add(1, Ordering::SeqCst); - let uuid = Uuid::from_fields(0, 0, 0, &[1, 2, 3, 4, 5, 6, 7, 8]); + let uuid = Uuid::from_fields( + 0xa1a2a3a4, + 0xb1b2, + 0xc1b2, + &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x42], + ); uuid.as_u128() as usize + counter + 3 } diff --git a/src/vm.rs b/src/vm.rs index 74ddc35..46066e1 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,9 +1,6 @@ use core::fmt; -use crate::{ - gc::TriColor, - object::{Object, TypeValue}, -}; +use crate::object::{Object, TypeValue}; #[derive(Debug, PartialEq, Default, Clone)] pub enum GCStatus { @@ -32,10 +29,6 @@ pub enum OpCode { #[derive(Debug, PartialEq, Default, Clone)] pub struct VirtualMachine { - /// heap manages the runtime, which is a collection of memory regions. - /// - /// The runtime uses this memory to hold heap blocks that it fills up with values - /// in response to allocation requests pub heap: Vec, pub stack: Vec, pub op_codes: Vec, @@ -50,21 +43,8 @@ pub struct VirtualMachine { pub gc_status: GCStatus, } -pub trait VMTrait { - fn new(max_stack_size: usize, threshold: f64) -> Result - where - Self: Sized; - fn push(&mut self, obj: Object) -> Result; - fn pop(&mut self) -> Result; - fn len(&self) -> usize; - fn is_empty(&self) -> bool; - fn to_string(&self) -> String; - - // fn mark(&mut self); -} - -impl VMTrait for VirtualMachine { - fn new(max_stack_size: usize, threshold: f64) -> Result { +impl VirtualMachine { + pub fn new(max_stack_size: usize, threshold: f64) -> Result { if threshold <= 0.0 || threshold >= 100.0 { return Err(VMError::InvalidRangeOfThreshold); } @@ -76,7 +56,7 @@ impl VMTrait for VirtualMachine { }) } - fn push(&mut self, obj: Object) -> Result { + pub fn push(&mut self, obj: Object) -> Result { if self.len() >= self.max_stack_size { self.op_codes.push(OpCode::Halt); return Err(VMError::StackOverflow); @@ -84,81 +64,48 @@ impl VMTrait for VirtualMachine { self.stack.push(obj.to_owned()); self.op_codes.push(OpCode::Push(obj.value.unwrap())); - self.first_object = Some(self.stack[0].to_owned()); + self.update_first_object(); + self.update_num_object(); Ok(self.len()) } - fn pop(&mut self) -> Result { + pub fn pop(&mut self) -> Result { if self.is_empty() { self.op_codes.push(OpCode::Halt); return Err(VMError::StackUnderflow); } - let obj = self.stack.pop().unwrap(); + let _obj = self.stack.pop().unwrap(); self.op_codes.push(OpCode::Pop); - self.num_objects -= 1; + self.update_first_object(); + self.update_num_object(); - Ok(obj) + Ok(self.len()) } - fn len(&self) -> usize { + pub fn len(&self) -> usize { + if self.is_empty() { + return 0; + } + self.stack.len() } - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.stack.is_empty() } - fn to_string(&self) -> String { - format!( - "VM: {{\nstack: {:?},\nop_codes: {:?},\nmax_stack_size: {},\nthreshold: {},\nnum_objects: {},\nfirst_object: {:?},\ngc_confidence: {},\ntrigger_gc: {},\ngc_status: {}\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 - ) + fn update_num_object(&mut self) -> usize { + self.num_objects = self.heap.len(); + self.num_objects } - // fn mark(&mut self) { - // self.op_codes.push(OpCode::Mark); - // let mut mark_stack = Vec::new(); - - // while let Some(mut obj) = self.stack.pop() { - // if obj.marked == TriColor::White { - // obj.marked = TriColor::Gray; - // mark_stack.push(obj.clone()); - // } - - // if obj.reference.len() > 0 { - // let mut ref_obj = obj.reference.pop().unwrap(); - // if ref_obj.marked == TriColor::White { - // ref_obj.marked = TriColor::Gray; - // mark_stack.push(ref_obj.clone()); - // } - // obj.reference.push(ref_obj); - // } - // } - - // while let Some(mut obj) = mark_stack.pop() { - // if obj.marked == TriColor::Gray { - // obj.marked = TriColor::Black; - // } - - // if obj.reference.len() > 0 { - // let mut ref_obj = obj.reference.pop().unwrap(); - // if ref_obj.marked == TriColor::Gray { - // ref_obj.marked = TriColor::Black; - // } - // obj.reference.push(ref_obj); - // } - // } - // } + fn update_first_object(&mut self) -> bool { + self.first_object = self.stack.first().map(|obj| obj.to_owned()); + + self.first_object.is_some() + } } impl fmt::Display for VMError { @@ -174,6 +121,24 @@ impl fmt::Display for VMError { } } +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}}", + 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 + ) + } +} + impl fmt::Display for GCStatus { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/tests/heap_test.rs b/tests/heap_test.rs index 481b4a6..3774087 100644 --- a/tests/heap_test.rs +++ b/tests/heap_test.rs @@ -1,6 +1,9 @@ #[cfg(test)] mod heap_tests { - use gc_simulator::{heap::Heap, object::{Object, ObjectTrait}}; + use gc_simulator::{ + heap::Heap, + object::{Address, Field, Object, ObjectTrait}, + }; #[test] fn test_create_new_heap() { @@ -10,12 +13,6 @@ mod heap_tests { assert_eq!(heap.objects.is_empty(), true); } - #[test] - #[ignore] - fn test_lookup() { - assert!(true); - } - #[test] fn test_next_object_address() { let mut heap = Heap::new(100, 0); @@ -64,6 +61,7 @@ mod heap_tests { h.objects.insert(o2.get_address(), o2.to_owned()); h.objects.insert(o3.get_address(), o3.to_owned()); + // println!("heap: {:?}", h); assert_eq!(h.next_object(o1.get_address()), Some(&o2)); assert_eq!(h.next_object(o2.get_address()), Some(&o3)); assert_eq!(h.next_object(o3.get_address()), None); @@ -112,4 +110,4 @@ mod heap_tests { assert_eq!(h.aligned_position(i), i); } } -} \ No newline at end of file +} diff --git a/tests/vm_test.rs b/tests/vm_test.rs index 41b131e..330947a 100644 --- a/tests/vm_test.rs +++ b/tests/vm_test.rs @@ -2,7 +2,7 @@ mod vm_tests { use gc_simulator::{ object::{Object, ObjectTrait, TypeValue}, - vm::{OpCode, VMError, VMTrait, VirtualMachine}, + vm::{OpCode, VMError, VirtualMachine}, }; static THRESHOLD: f64 = 0.75; @@ -82,17 +82,31 @@ mod vm_tests { assert_eq!(vm.pop().unwrap_err(), VMError::StackUnderflow); } - // #[test] - // fn test_op_code() { - // let max_stack_size = 10; - // let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); + #[test] + fn test_op_code() { + let max_stack_size = 10; + let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); - // let value = Object::new(String::from("test"), TypeValue::Int(1)); - // vm.push(value).unwrap(); - // vm.pop().unwrap(); + let value = Object::new(String::from("test"), TypeValue::Int(1)); + vm.push(value).unwrap(); + vm.pop().unwrap(); - // assert_eq!(vm.op_codes.len(), 2); - // assert_eq!(vm.op_codes[0], OpCode::Push(TypeValue::Int(1))); - // assert_eq!(vm.op_codes[1], OpCode::Pop); - // } + assert_eq!(vm.op_codes.len(), 2); + assert_eq!(vm.op_codes[0], OpCode::Push(TypeValue::Int(1))); + assert_eq!(vm.op_codes[1], OpCode::Pop); + } + + #[test] + fn test_get_first_object() { + let max_stack_size = 10; + let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); + + let value = Object::new(String::from("test"), TypeValue::Int(1)); + vm.push(value.clone()).unwrap(); + + assert_eq!(vm.first_object, Some(value)); + + vm.pop().unwrap(); + assert_eq!(vm.first_object, None); + } }