Skip to content

Commit

Permalink
heap
Browse files Browse the repository at this point in the history
  • Loading branch information
notJoon committed Nov 24, 2023
1 parent e05f1dd commit ce6d2ee
Show file tree
Hide file tree
Showing 8 changed files with 837 additions and 44 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ rand = "0.8.5"
[dependencies.uuid]
version = "1.6.1"
features = [
"v4", # Lets you generate random UUIDs
"v1", # Lets you generate random UUIDs
"fast-rng", # Use a faster (but still sufficiently random) RNG
"macro-diagnostics", # Enable better diagnostics for compile-time UUIDs
]

[profile.release]
debug = true

[profile.bench]
debug = true
27 changes: 23 additions & 4 deletions src/object.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use core::fmt;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{collections::HashSet, default};

use rand::Rng;
use uuid::Uuid;

use crate::gc::TriColor;

pub type ObjectAddress = usize;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

#[derive(Debug, PartialEq, Clone)]
pub struct Object {
/// The name of the object
Expand Down Expand Up @@ -61,8 +65,9 @@ pub trait ObjectTrait {
/// Returns the size of the object (field size + header size) in bytes
fn object_size(&self) -> usize;
/// Returns a randomly generated isolate object
fn create_random_object() -> Self;
fn create_random_object(name: Option<&str>) -> Self;
fn to_string(&self) -> String;
fn inject_address(&mut self, addr: ObjectAddress);
}

impl ObjectTrait for Object {
Expand Down Expand Up @@ -112,7 +117,12 @@ impl ObjectTrait for Object {
self.header.marked != TriColor::White
}

fn create_random_object() -> Self {
// testing purpose
fn create_random_object(name: Option<&str>) -> Self {
let ident = match name {
Some(name) => name.to_owned(),
None => String::from("Random Object"),
};
let mut rng = rand::thread_rng();

let num_fields = rng.gen_range(0..10);
Expand All @@ -125,7 +135,7 @@ impl ObjectTrait for Object {
.collect();

Self {
ident: String::from("Random Object"),
ident,
fields,
..Default::default()
}
Expand All @@ -141,6 +151,11 @@ impl ObjectTrait for Object {
s.push_str(&format!("Fields: {:?}\n", self.fields));
s
}

// testing purpose
fn inject_address(&mut self, addr: ObjectAddress) {
self.addr = addr;
}
}

impl Field {
Expand All @@ -165,7 +180,11 @@ impl default::Default for Object {
next: None,
marked: TriColor::White,
},
addr: uuid::Uuid::new_v4().as_u128() as usize,
addr: {
let counter = COUNTER.fetch_add(1, Ordering::SeqCst);
let uuid = Uuid::from_fields(0, 0, 0, &[1, 2, 3, 4, 5, 6, 7, 8]);
uuid.as_u128() as usize + counter + 3
},
references: HashSet::new(),
fields: vec![],
}
Expand Down
Empty file removed src/stack.rs
Empty file.
660 changes: 660 additions & 0 deletions tarpaulin-report.html

Large diffs are not rendered by default.

105 changes: 104 additions & 1 deletion tests/heap_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#[cfg(test)]
mod heap_tests {
use gc_simulator::heap::Heap;
use gc_simulator::{heap::Heap, object::{Object, ObjectTrait, ObjectAddress, Field, TypeValue}};

#[test]
fn test_create_new_heap() {
Expand All @@ -9,4 +9,107 @@ mod heap_tests {
assert_eq!(heap.calculate_free_memory(), 100);
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);

let obj1 = Object::create_random_object(Some("o1"));
let obj2 = Object::create_random_object(Some("o2"));
let obj3 = Object::create_random_object(Some("o3"));

heap.objects.insert(obj1.get_address(), obj1.to_owned());
heap.objects.insert(obj2.get_address(), obj2.to_owned());
heap.objects.insert(obj3.get_address(), obj3.to_owned());

assert_eq!(heap.next_object(obj1.get_address() - 1), Some(&obj1));
assert_eq!(heap.next_object(obj1.get_address()), Some(&obj2));
assert_eq!(heap.next_object(obj2.get_address()), Some(&obj3));

assert_eq!(heap.next_object(obj3.get_address()), None);
assert_eq!(heap.next_object(obj3.get_address() + 10), None);
}

#[test]
fn test_last_object_addr() {
let mut h = Heap::new(100, 0);

assert_eq!(h.last_object(), None);

let obj1 = Object::create_random_object(Some("o1"));
h.objects.insert(obj1.get_address(), obj1.to_owned());
assert_eq!(h.last_object(), Some(&obj1));

let obj2 = Object::create_random_object(Some("o2"));
h.objects.insert(obj2.get_address(), obj2.to_owned());
assert_eq!(h.last_object(), Some(&obj2));
}

#[test]
fn test_next_prev_object_address() {
let mut h = Heap::new(100, 0);

// ad multiple objects and navigate them using next_object and prev_object
let o1 = Object::create_random_object(Some("o1"));
let o2 = Object::create_random_object(Some("o2"));
let o3 = Object::create_random_object(Some("o3"));

h.objects.insert(o1.get_address(), o1.to_owned());
h.objects.insert(o2.get_address(), o2.to_owned());
h.objects.insert(o3.get_address(), o3.to_owned());

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);

assert_eq!(h.prev_object(o1.get_address() - 100), None);
assert_eq!(h.next_object(o3.get_address() + 100), None);
}

#[test]
fn test_calculate_free_memory() {
let heap = Heap::new(100, 4);
assert_eq!(heap.calculate_free_memory(), 100);
}

#[test]
fn test_merge_free_ranges() {
let mut heap = Heap::new(100, 4);
heap.merge_free_ranges().unwrap();
assert_eq!(heap.calculate_free_memory(), 100);
}

#[test]
fn test_align_position() {
let h = Heap::new(100, 4);

assert_eq!(h.aligned_position(0), 0);
assert_eq!(h.aligned_position(1), 4);
assert_eq!(h.aligned_position(2), 4);
assert_eq!(h.aligned_position(3), 4);
assert_eq!(h.aligned_position(4), 4);
assert_eq!(h.aligned_position(5), 8);

let h = Heap::new(100, 8);

assert_eq!(h.aligned_position(0), 0);
assert_eq!(h.aligned_position(5), 8);
assert_eq!(h.aligned_position(8), 8);
assert_eq!(h.aligned_position(9), 16);
}

#[test]
fn test_no_align() {
let h = Heap::new(100, 0);

for i in 0..10 {
assert_eq!(h.aligned_position(i), i);
}
}
}
25 changes: 23 additions & 2 deletions tests/object_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,29 @@ mod object_tests {

#[test]
fn test_create_random_object() {
let obj1 = Object::create_random_object();
let obj1 = Object::create_random_object(Some("obj1"));
println!("{}", obj1.to_string());
println!("addr: {:?}", obj1.get_address());
println!("addr: {:?}\n", obj1.get_address());

println!("--------");

let obj2 = Object::create_random_object(Some("obj2"));
println!("{}", obj2.to_string());
println!("addr: {:?}\n", obj2.get_address());

println!("--------");

let obj3 = Object::create_random_object(Some("obj3"));
println!("{}", obj3.to_string());
println!("addr: {:?}\n", obj3.get_address());
}

#[test]
fn test_inject_address() {
let mut obj1 = Object::create_random_object(Some("obj1"));
let obj2 = Object::create_random_object(Some("obj2"));

obj1.inject_address(obj2.get_address());
assert_eq!(obj1.addr, obj2.get_address());
}
}
49 changes: 13 additions & 36 deletions tests/vm_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,10 @@ mod vm_tests {
for i in 0..max_stack_size {
let value = Object::new(String::from(format!("test{}", i)), TypeValue::Int(i as i32));
vm.push(value).unwrap();
assert_eq!(vm.len(), i + 1);
assert_eq!(vm.num_objects, i + 1);
}

assert_eq!(vm.len(), max_stack_size);

for i in (0..max_stack_size).rev() {
let value = Object::new(String::from(format!("test{}", i)), TypeValue::Int(i as i32));
assert_eq!(vm.pop().unwrap(), value);
assert_eq!(vm.stack.len(), i + 1);
println!("stack: {:?}", vm.stack);
}

assert_eq!(vm.len(), 0);
}

#[test]
Expand All @@ -90,32 +82,17 @@ 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);
}

#[test]
fn test_vm_debug_string() {
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();
vm.pop().unwrap_err();

assert_eq!(
vm.to_string(),
"VM: {\nstack: [],\nop_codes: [Push(Int(1)), Pop, Halt],\nmax_stack_size: 10,\nthreshold: 7,\nnum_objects: 0,\nfirst_object: None,\ngc_confidence: 0,\ntrigger_gc: false,\ngc_status: Idle\n}");
}
// 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);
// }
}

0 comments on commit ce6d2ee

Please sign in to comment.