From eab3cd2b9e13cb1ad6e9f3044dd8a542ccc8010b Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Fri, 24 Nov 2023 11:30:02 +0900 Subject: [PATCH 1/2] add opcodes --- src/gc.rs | 45 +++++++++++ src/lib.rs | 2 +- src/object.rs | 10 ++- src/types.rs | 18 ----- src/vm.rs | 87 ++++++++++++---------- tests/object_test.rs | 3 +- tests/vm_test.rs | 173 ++++++++++++++++++++++--------------------- 7 files changed, 193 insertions(+), 145 deletions(-) create mode 100644 src/gc.rs delete mode 100644 src/types.rs diff --git a/src/gc.rs b/src/gc.rs new file mode 100644 index 0000000..9bd62f6 --- /dev/null +++ b/src/gc.rs @@ -0,0 +1,45 @@ +use std::fmt; + +use crate::{controller::PIController, vm::VM}; + +pub trait GarbageCollector { + fn collect(&self, vm: &mut VM); + fn ty(&self) -> GCType; + fn new_instance(&self) -> Box; +} + +pub struct TriColorGC { + pub color: TriColor, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum GCType { + MarkAndSweep, +} + +#[derive(Debug, PartialEq, Clone)] +pub enum TriColor { + White, + Gray, + Black, +} + +impl fmt::Display for TriColor { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TriColor::White => write!(f, "White: Not visited"), + TriColor::Gray => write!(f, "Gray: Visiting"), + TriColor::Black => write!(f, "Black: Visited"), + } + } +} + +pub struct MarkAndSweep { + pub pi: PIController, +} + +// impl GarbageCollector for MarkAndSweep { +// fn collect(&self, vm: &mut VM) { + +// } +// } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 17a6560..0225d82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ pub mod controller; pub mod mem; pub mod object; -pub mod types; pub mod vm; +pub mod gc; diff --git a/src/object.rs b/src/object.rs index 0cb0913..b6aab24 100644 --- a/src/object.rs +++ b/src/object.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::default; use std::rc::Rc; -use crate::types::TriColor; +use crate::gc::TriColor; #[derive(Debug, PartialEq, Clone)] pub enum TypeValue { @@ -87,3 +87,11 @@ impl default::Default for Object { } } } + +// pub trait ObjectMarker { +// fn mark_from_root(&self, vm: &mut VM) { +// for obj in &vm.stack { +// obj.co +// } +// } +// } \ No newline at end of file diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index 44795e7..0000000 --- a/src/types.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::fmt; - -#[derive(Debug, PartialEq, Clone)] -pub enum TriColor { - White, - Gray, - Black, -} - -impl fmt::Display for TriColor { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TriColor::White => write!(f, "White: Not visited"), - TriColor::Gray => write!(f, "Gray: Visiting"), - TriColor::Black => write!(f, "Black: Visited"), - } - } -} diff --git a/src/vm.rs b/src/vm.rs index ce3d0a2..c5944bf 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,9 +1,6 @@ use core::fmt; -use crate::{ - controller::PIController, - object::{Object, ObjectTrait, TypeValue}, -}; +use crate::object::{Object, TypeValue}; #[derive(Debug, PartialEq, Default)] pub enum GCStatus { @@ -20,16 +17,24 @@ pub enum VMError { InvalidRangeOfThreshold, } +#[derive(Debug, PartialEq, Clone, Default)] +pub enum OpCode { + #[default] + Halt, + Pop, + Push(TypeValue), +} + #[derive(Debug, PartialEq, Default)] pub struct VM { - pub stack: Vec<*mut Object>, + pub stack: Vec, + pub op_codes: Vec, pub max_stack_size: usize, pub threshold: usize, pub num_objects: usize, - pub first_object: Option<*mut Object>, + pub first_object: Option, - pi: PIController, pub gc_confidence: f64, pub trigger_gc: bool, pub gc_status: GCStatus, @@ -39,13 +44,11 @@ pub trait VMTrait { fn new(max_stack_size: usize, threshold: f64) -> Result where Self: Sized; - fn push(&mut self, obj: *mut Object) -> Result; - fn pop(&mut self) -> Result<*mut Object, VMError>; - fn new_object(&mut self, ident: String, value: TypeValue) -> *mut Object; - fn push_int(&mut self, value: i32) -> Result; + fn push(&mut self, obj: Object) -> Result; + fn pop(&mut self) -> Result; fn len(&self) -> usize; fn is_empty(&self) -> bool; - fn update_gc_confidence(&mut self) -> f64; + fn to_string(&self) -> String; } impl VMTrait for VM { @@ -61,38 +64,28 @@ impl VMTrait for VM { }) } - fn push(&mut self, obj: *mut Object) -> Result { + fn push(&mut self, obj: Object) -> Result { if self.len() >= self.max_stack_size { + self.op_codes.push(OpCode::Halt); return Err(VMError::StackOverflow); } - self.stack.push(obj); + self.stack.push(obj.to_owned()); + self.op_codes.push(OpCode::Push(obj.value.unwrap())); + Ok(self.len()) } - fn pop(&mut self) -> Result<*mut Object, VMError> { + 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(); - Ok(obj) - } - - fn new_object(&mut self, ident: String, value: TypeValue) -> *mut Object { - let obj = Box::new(Object::new(ident, value)); - let obj_ptr = Box::into_raw(obj); - - self.first_object = Some(obj_ptr); - self.num_objects += 1; - - obj_ptr - } + self.op_codes.push(OpCode::Pop); - fn push_int(&mut self, value: i32) -> Result { - let obj = self.new_object(String::from("int"), TypeValue::Int(value)); - self.push(obj)?; - Ok(value) + Ok(obj) } fn len(&self) -> usize { @@ -103,15 +96,19 @@ impl VMTrait for VM { self.stack.is_empty() } - fn update_gc_confidence(&mut self) -> f64 { - let current_metric = self.stack.len() as f64 / self.max_stack_size as f64 * 100.0; - let set_point = self.threshold as f64; - - if let Ok(output) = self.pi.update(current_metric, set_point, 0.0, 0.0) { - self.gc_confidence = output; - } - - self.gc_confidence + 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 + ) } } @@ -137,3 +134,13 @@ impl fmt::Display for GCStatus { } } } + +impl fmt::Display for OpCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + OpCode::Push(ref i) => write!(f, "Push: {}", i), + OpCode::Pop => write!(f, "Pop"), + OpCode::Halt => write!(f, "Halt"), + } + } +} \ No newline at end of file diff --git a/tests/object_test.rs b/tests/object_test.rs index ed18b18..534d9c9 100644 --- a/tests/object_test.rs +++ b/tests/object_test.rs @@ -1,7 +1,6 @@ #[cfg(test)] mod object_tests { - use gc_simulator::object::{Object, ObjectTrait, TypeValue}; - use gc_simulator::types::TriColor; + use gc_simulator::{object::{Object, ObjectTrait, TypeValue}, gc::TriColor}; #[test] fn test_new() { diff --git a/tests/vm_test.rs b/tests/vm_test.rs index 8c3c00e..7456f72 100644 --- a/tests/vm_test.rs +++ b/tests/vm_test.rs @@ -1,8 +1,8 @@ #[cfg(test)] mod vm_tests { use gc_simulator::{ - object::TypeValue, - vm::{VMError, VMTrait, VM}, + object::{TypeValue, Object, ObjectTrait}, + vm::{VMError, VMTrait, VM, OpCode}, }; static THRESHOLD: f64 = 0.75; @@ -30,104 +30,111 @@ mod vm_tests { } #[test] - fn test_push() { - let mut vm = VM::new(10, THRESHOLD).unwrap(); + fn test_push_objects_to_vm() { + let max_stack_size = 10; + let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); - let obj = vm.new_object(String::from("test"), TypeValue::Int(1)); - vm.push(obj).unwrap(); - assert_eq!(vm.stack.len(), 1); + for i in 0..max_stack_size-1 { + let value = Object::new( + String::from(format!("test{}", i)), + TypeValue::Int(i as i32) + ); + vm.push(value).unwrap(); + } - let obj2 = vm.new_object(String::from("test2"), TypeValue::Int(2)); - vm.push(obj2).unwrap(); - assert_eq!(vm.stack.len(), 2); + assert_eq!(vm.len(), max_stack_size-1); } #[test] - fn test_pop() { - let mut vm = VM::new(10, THRESHOLD).unwrap(); - - let obj = vm.new_object(String::from("test"), TypeValue::Int(1)); - vm.push(obj).unwrap(); - assert_eq!(vm.stack.len(), 1); - - let obj2 = vm.new_object(String::from("test2"), TypeValue::Int(2)); - vm.push(obj2).unwrap(); - assert_eq!(vm.stack.len(), 2); - - let obj3 = vm.pop().unwrap(); - assert_eq!(obj3, obj2); - assert_eq!(vm.stack.len(), 1); - - let obj4 = vm.pop().unwrap(); - assert_eq!(obj4, obj); - assert_eq!(vm.stack.is_empty(), true); + fn test_stack_overflow() { + let max_stack_size = 10; + let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + + 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(), max_stack_size); + assert_eq!( + vm.push(Object::new(String::from("test"), + TypeValue::Int(1))).unwrap_err(), + VMError::StackOverflow + ); } #[test] - fn test_stack_overflow() { - let mut vm = VM::new(1, THRESHOLD).unwrap(); - - let obj = vm.new_object(String::from("test"), TypeValue::Int(1)); - vm.push(obj).unwrap(); - assert_eq!(vm.stack.len(), 1); - - let obj2 = vm.new_object(String::from("test2"), TypeValue::Int(2)); - let result = vm.push(obj2); - assert_eq!(result, Err(VMError::StackOverflow)); + fn test_pop() { + let max_stack_size = 10; + let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + + 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(), 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.len(), 0); } #[test] - fn test_stack_underflow() { - let mut vm = VM::new(1, THRESHOLD).unwrap(); + fn stack_underflow() { + let max_stack_size = 10; + let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); - let result = vm.pop(); - assert_eq!(result, Err(VMError::StackUnderflow)); + assert_eq!( + vm.pop().unwrap_err(), + VMError::StackUnderflow + ); } #[test] - fn test_new_object() { - let mut vm = VM::new(10, THRESHOLD).unwrap(); - - let obj = vm.new_object(String::from("test"), TypeValue::Int(1)); - assert_eq!(vm.first_object, Some(obj)); - assert_eq!(vm.num_objects, 1); - - let obj2 = vm.new_object(String::from("test2"), TypeValue::Int(2)); - assert_eq!(vm.first_object, Some(obj2)); - assert_eq!(vm.num_objects, 2); + fn test_op_code() { + let max_stack_size = 10; + let mut vm = VM::new(max_stack_size, THRESHOLD).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_push_int() { - let mut vm = VM::new(10, THRESHOLD).unwrap(); - - let result = vm.push_int(1); - assert_eq!(result, Ok(1)); - assert_eq!(vm.stack.len(), 1); - - let result = vm.push_int(2); - assert_eq!(result, Ok(2)); - assert_eq!(vm.stack.len(), 2); + fn test_vm_debug_string() { + let max_stack_size = 10; + let mut vm = VM::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}"); } - - // #[test] - // fn performance_test() { - // let mut vm = VM::new(10, THRESHOLD).unwrap(); - - // let mut i = 0; - // while i < 1000000 { - // let result = vm.push_int(i); - // assert_eq!(result, Ok(i)); - // assert_eq!(vm.stack.len(), i as usize + 1); - // i += 1; - // } - - // let mut i = 0; - // while i < 1000000 { - // let result = vm.pop(); - // assert_eq!(result, Ok(vm.stack[i as usize])); - // assert_eq!(vm.stack.len(), 1000000 - i as usize - 1); - // i += 1; - // } - // } } From 5165d9e705cdbd0dad9b841c4f4fbb920864f80a Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Fri, 24 Nov 2023 12:20:05 +0900 Subject: [PATCH 2/2] save --- src/gc.rs | 10 +++++---- src/heap.rs | 6 ++++++ src/lib.rs | 1 + src/object.rs | 20 +++++------------ src/stack.rs | 0 src/vm.rs | 56 ++++++++++++++++++++++++++++++++++++++++++------ tests/vm_test.rs | 18 ++++++++-------- 7 files changed, 77 insertions(+), 34 deletions(-) create mode 100644 src/heap.rs create mode 100644 src/stack.rs diff --git a/src/gc.rs b/src/gc.rs index 9bd62f6..134d885 100644 --- a/src/gc.rs +++ b/src/gc.rs @@ -1,11 +1,13 @@ use std::fmt; -use crate::{controller::PIController, vm::VM}; +use crate::{controller::PIController, vm::VirtualMachine}; pub trait GarbageCollector { - fn collect(&self, vm: &mut VM); + fn collect(&self, vm: &mut VirtualMachine); fn ty(&self) -> GCType; fn new_instance(&self) -> Box; + fn adjust_confidence(&mut self, vm: &mut VirtualMachine); + fn trigger_gc(&mut self, vm: &mut VirtualMachine); } pub struct TriColorGC { @@ -40,6 +42,6 @@ pub struct MarkAndSweep { // impl GarbageCollector for MarkAndSweep { // fn collect(&self, vm: &mut VM) { - + // } -// } \ No newline at end of file +// } diff --git a/src/heap.rs b/src/heap.rs new file mode 100644 index 0000000..598a812 --- /dev/null +++ b/src/heap.rs @@ -0,0 +1,6 @@ +use std::collections::BTreeSet; + +// #[derive(Debug, PartialEq, Clone, Default)] +// pub struct Heap { +// pub roots: BTreeSet<> +// } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 0225d82..01cc1d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,4 @@ pub mod mem; pub mod object; pub mod vm; pub mod gc; +pub mod heap; \ No newline at end of file diff --git a/src/object.rs b/src/object.rs index b6aab24..4198c67 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,7 +1,5 @@ use core::fmt; -use std::cell::RefCell; use std::default; -use std::rc::Rc; use crate::gc::TriColor; @@ -22,14 +20,14 @@ impl fmt::Display for TypeValue { pub struct Object { pub ident: String, pub value: Option, - pub reference: Vec>>, + pub reference: Vec, pub marked: TriColor, } pub trait ObjectTrait { fn new(ident: String, value: TypeValue) -> Self; fn add_reference(&mut self, object: Object) -> usize; - fn delete_reference(&mut self, object: Rc>) -> usize; + fn delete_reference(&mut self, object: Object) -> usize; fn len(&self) -> usize; fn is_empty(&self) -> bool; fn to_string(&self) -> String; @@ -47,12 +45,12 @@ impl ObjectTrait for Object { } fn add_reference(&mut self, object: Object) -> usize { - self.reference.push(Rc::new(RefCell::new(object))); + self.reference.push(object); self.reference.len() } - fn delete_reference(&mut self, object: Rc>) -> usize { - self.reference.retain(|x| !Rc::ptr_eq(x, &object)); + fn delete_reference(&mut self, object: Object) -> usize { + self.reference.retain(|x| x != &object); self.reference.len() } @@ -87,11 +85,3 @@ impl default::Default for Object { } } } - -// pub trait ObjectMarker { -// fn mark_from_root(&self, vm: &mut VM) { -// for obj in &vm.stack { -// obj.co -// } -// } -// } \ No newline at end of file diff --git a/src/stack.rs b/src/stack.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/vm.rs b/src/vm.rs index c5944bf..20b4dcd 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,8 +1,11 @@ use core::fmt; -use crate::object::{Object, TypeValue}; +use crate::{ + gc::TriColor, + object::{Object, TypeValue}, +}; -#[derive(Debug, PartialEq, Default)] +#[derive(Debug, PartialEq, Default, Clone)] pub enum GCStatus { #[default] Idle, @@ -23,10 +26,12 @@ pub enum OpCode { Halt, Pop, Push(TypeValue), + Mark, + Sweep, } -#[derive(Debug, PartialEq, Default)] -pub struct VM { +#[derive(Debug, PartialEq, Default, Clone)] +pub struct VirtualMachine { pub stack: Vec, pub op_codes: Vec, pub max_stack_size: usize, @@ -49,9 +54,11 @@ pub trait VMTrait { fn len(&self) -> usize; fn is_empty(&self) -> bool; fn to_string(&self) -> String; + + fn mark(&mut self); } -impl VMTrait for VM { +impl VMTrait for VirtualMachine { fn new(max_stack_size: usize, threshold: f64) -> Result { if threshold <= 0.0 || threshold >= 100.0 { return Err(VMError::InvalidRangeOfThreshold); @@ -110,6 +117,41 @@ impl VMTrait for VM { self.gc_status ) } + + 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); + } + } + } } impl fmt::Display for VMError { @@ -141,6 +183,8 @@ impl fmt::Display for OpCode { OpCode::Push(ref i) => write!(f, "Push: {}", i), OpCode::Pop => write!(f, "Pop"), OpCode::Halt => write!(f, "Halt"), + OpCode::Mark => write!(f, "Mark"), + OpCode::Sweep => write!(f, "Sweep"), } } -} \ No newline at end of file +} diff --git a/tests/vm_test.rs b/tests/vm_test.rs index 7456f72..fce1783 100644 --- a/tests/vm_test.rs +++ b/tests/vm_test.rs @@ -2,7 +2,7 @@ mod vm_tests { use gc_simulator::{ object::{TypeValue, Object, ObjectTrait}, - vm::{VMError, VMTrait, VM, OpCode}, + vm::{VMError, VMTrait, VirtualMachine, OpCode}, }; static THRESHOLD: f64 = 0.75; @@ -10,7 +10,7 @@ mod vm_tests { #[test] fn test_new_vm() { let max_stack_size = 10; - let vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + let vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); assert_eq!(vm.max_stack_size, max_stack_size); assert_eq!(vm.stack, vec![]); @@ -21,7 +21,7 @@ mod vm_tests { #[test] fn test_max_stack_size_exceed_max_int() { let max_stack_size = usize::MAX; - let vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + let vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); assert_eq!(vm.max_stack_size, max_stack_size); assert_eq!(vm.stack, vec![]); @@ -32,7 +32,7 @@ mod vm_tests { #[test] fn test_push_objects_to_vm() { let max_stack_size = 10; - let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); for i in 0..max_stack_size-1 { let value = Object::new( @@ -48,7 +48,7 @@ mod vm_tests { #[test] fn test_stack_overflow() { let max_stack_size = 10; - let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); for i in 0..max_stack_size { let value = Object::new( @@ -69,7 +69,7 @@ mod vm_tests { #[test] fn test_pop() { let max_stack_size = 10; - let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); for i in 0..max_stack_size { let value = Object::new( @@ -95,7 +95,7 @@ mod vm_tests { #[test] fn stack_underflow() { let max_stack_size = 10; - let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); assert_eq!( vm.pop().unwrap_err(), @@ -106,7 +106,7 @@ mod vm_tests { #[test] fn test_op_code() { let max_stack_size = 10; - let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); let value = Object::new( String::from("test"), @@ -123,7 +123,7 @@ mod vm_tests { #[test] fn test_vm_debug_string() { let max_stack_size = 10; - let mut vm = VM::new(max_stack_size, THRESHOLD).unwrap(); + let mut vm = VirtualMachine::new(max_stack_size, THRESHOLD).unwrap(); let value = Object::new( String::from("test"),