diff --git a/src/vm/array.rs b/src/vm/array.rs index b397031..22c0428 100644 --- a/src/vm/array.rs +++ b/src/vm/array.rs @@ -16,7 +16,7 @@ pub enum DvmArray { Booleans(Vec), Objects(Vec>>), Arrays(Vec>>), - ConstantPointers(Vec), + Strings(Vec>) } impl DvmArray { @@ -30,7 +30,7 @@ impl DvmArray { DvmArray::Booleans(vec) => DvmValue::Boolean(vec[index]), DvmArray::Objects(vec) => DvmValue::Object(vec[index].clone()), DvmArray::Arrays(vec) => DvmValue::Array(vec[index].clone()), - DvmArray::ConstantPointers(vec) => DvmValue::ConstantPointer(vec[index].clone()), + DvmArray::Strings(vec) => DvmValue::String(vec[index].clone()), } } @@ -60,8 +60,8 @@ impl DvmArray { DvmArray::Arrays(vec) => { vec[index] = value.expect_array(); } - DvmArray::ConstantPointers(vec) => { - vec[index] = value.expect_constant_pointer(); + DvmArray::Strings(vec) => { + vec[index] = value.expect_string(); } } } @@ -89,7 +89,7 @@ pub enum DvmArrayIter<'a> { Booleans(Iter<'a, bool>), Objects(Iter<'a, Rc>>), Arrays(Iter<'a, Rc>>), - ConstantPointers(Iter<'a, DvmPointer>), + Strings(Iter<'a, Rc>), } impl<'a> Iterator for DvmArrayIter<'a> { @@ -104,9 +104,7 @@ impl<'a> Iterator for DvmArrayIter<'a> { DvmArrayIter::Booleans(iter) => iter.next().map(|b| DvmValue::Boolean(*b)), DvmArrayIter::Objects(iter) => iter.next().map(|o| DvmValue::Object(o.clone())), DvmArrayIter::Arrays(iter) => iter.next().map(|a| DvmValue::Array(a.clone())), - DvmArrayIter::ConstantPointers(iter) => { - iter.next().map(|p| DvmValue::ConstantPointer(p.clone())) - } + DvmArrayIter::Strings(iter) => iter.next().map(|s| DvmValue::String(s.clone())), } } } @@ -125,7 +123,7 @@ impl<'a> IntoIterator for &'a DvmArray { DvmArray::Booleans(v) => DvmArrayIter::Booleans(v.iter()), DvmArray::Objects(v) => DvmArrayIter::Objects(v.iter()), DvmArray::Arrays(v) => DvmArrayIter::Arrays(v.iter()), - DvmArray::ConstantPointers(v) => DvmArrayIter::ConstantPointers(v.iter()), + DvmArray::Strings(v) => DvmArrayIter::Strings(v.iter()), } } } diff --git a/src/vm/constant.rs b/src/vm/constant.rs new file mode 100644 index 0000000..4fbdb01 --- /dev/null +++ b/src/vm/constant.rs @@ -0,0 +1,17 @@ +#[derive(Debug, Clone)] +pub enum DvmConstant { + String(String), + Array(DvmConstantArray) +} + +#[derive(Debug, Clone)] +pub enum DvmConstantArray { + Bytes(Vec), + Ints(Vec), + Longs(Vec), + Doubles(Vec), + USizes(Vec), + Booleans(Vec), + Strings(Vec), + Arrays(Vec) +} \ No newline at end of file diff --git a/src/vm/instruction.rs b/src/vm/instruction.rs index 8e42022..d9c18f6 100644 --- a/src/vm/instruction.rs +++ b/src/vm/instruction.rs @@ -1,4 +1,5 @@ use std::rc::Rc; +use crate::vm::constant::DvmConstant; #[derive(Debug, Clone)] pub enum Instruction { @@ -29,8 +30,13 @@ pub enum Instruction { function_name: Rc, source_code_location: SourceCodeLocation, }, - PlatformCall { - platform_function_name: Rc, + InvokeStaticPlatform { + function_name: Rc, + source_code_location: SourceCodeLocation, + }, + InvokeObjectPlatform { + object_register: usize, + function_name: Rc, source_code_location: SourceCodeLocation, }, Add { @@ -107,10 +113,7 @@ pub enum Immediate { Double(f64), Usize(usize), Boolean(bool), - ConstantPointer { - raw_pointer: *const u8, - length: usize - }, + Constant(DvmConstant), Empty, } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index ba5129d..cbba5f5 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,4 +1,5 @@ mod array; +mod constant; mod field; mod function; pub mod implementation; @@ -15,10 +16,11 @@ pub mod util; pub mod value; mod virtual_method; +use crate::vm::array::DvmArray; +use crate::vm::constant::{DvmConstant, DvmConstantArray}; use crate::vm::implementation::DvmImplementation; use crate::vm::instruction::{Immediate, Instruction, Location, SourceCodeLocation}; use crate::vm::object::DvmObject; -use crate::vm::pointer::DvmPointer; use crate::vm::value::DvmValue; use function::DvmFunction; use std::cell::RefCell; @@ -26,22 +28,22 @@ use std::collections::HashMap; use std::fmt::Display; use std::rc::Rc; -fn dvm_panic(context: &DvmContext, message: &str) { +fn dvm_panic(state: &DvmState, message: &str) { println!("----"); println!("Deimos Virtual Machine: Panic!"); println!("{}", message); println!("----"); - println!("Current Instruction: {:?}", context.current_instruction); + println!("Current Instruction: {:?}", state.current_instruction); println!("Registers:"); - for (i, register) in context.registers.iter().enumerate() { + for (i, register) in state.registers.iter().enumerate() { println!("\tr{}: {:?}", i, register); } println!("Call stack:"); - for call in context.call_stack.iter() { + for call in state.call_stack.iter() { println!("\t{}", call); } println!("Stack:"); - for (i, value) in context.stack.iter().enumerate() { + for (i, value) in state.stack.iter().enumerate() { println!("\t{}: {}", i, value); } println!("----"); @@ -54,13 +56,33 @@ macro_rules! dvm_panic { }; } -pub type PlatformFunction = fn(context: &mut DvmContext); +pub type PlatformFunction = fn(state: &mut DvmState, context: &DvmContext); -pub struct DvmContext { +pub struct DvmState { call_stack: Vec, current_instruction: Option, registers: Vec, stack: Vec, +} + +impl DvmState { + pub fn new() -> Self { + DvmState { + call_stack: vec![], + current_instruction: None, + registers: vec![], + stack: vec![], + } + } + + pub fn pop_stack(&mut self) -> DvmValue { + self.stack.pop().unwrap_or_else(|| { + dvm_panic!(self, "Stack underflow!"); + }) + } +} + +pub struct DvmContext { implementations: HashMap>, static_functions: HashMap>, platform_functions: HashMap, @@ -69,21 +91,11 @@ pub struct DvmContext { impl DvmContext { pub fn new() -> Self { DvmContext { - call_stack: vec![], - current_instruction: None, - registers: vec![], - stack: vec![], implementations: HashMap::new(), static_functions: HashMap::new(), platform_functions: HashMap::new(), } } - - pub fn pop_stack(&mut self) -> DvmValue { - self.stack.pop().unwrap_or_else(|| { - dvm_panic!(self, "Stack underflow!"); - }) - } } pub struct DvmCall { @@ -114,16 +126,16 @@ fn update_index(index: &mut usize, offset: isize) { fn push_call_frame( function_name: Rc, source_code_location: SourceCodeLocation, - context: &mut DvmContext, + state: &mut DvmState, ) { - context.call_stack.push(DvmCall { + state.call_stack.push(DvmCall { function_name, source_code_location, }); } -fn pop_call_frame(context: &mut DvmContext) { - context.call_stack.pop(); +fn pop_call_frame(state: &mut DvmState) { + state.call_stack.pop(); } fn compute_index_with_offset( @@ -146,17 +158,17 @@ fn compute_index_with_offset( } } -fn copy_from_source(context: &DvmContext, source: &Location) -> DvmValue { +fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { match source { - Location::Register(register) => context.registers[*register].clone(), - Location::Stack { offset } => context.stack[*offset].clone(), + Location::Register(register) => state.registers[*register].clone(), + Location::Stack { offset } => state.stack[*offset].clone(), Location::Field { object_register, field_name, - } => context.registers[*object_register].map_object( + } => state.registers[*object_register].map_object( |o| o.borrow().read_field(field_name).clone(), |v| { - dvm_panic!(context, &format!("Expected an object, but found: {}", v)); + dvm_panic!(state, &format!("Expected an object, but found: {}", v)); }, ), Location::Array { @@ -164,30 +176,30 @@ fn copy_from_source(context: &DvmContext, source: &Location) -> DvmValue { index_register, offset, } => { - let index = compute_index_with_offset(&context.registers, *index_register, offset); - context.registers[*array_register].map_array( + let index = compute_index_with_offset(&state.registers, *index_register, offset); + state.registers[*array_register].map_array( |a| a.borrow().read_element(index), |v| { - dvm_panic!(context, &format!("Expected an array, but found: {}", v)); + dvm_panic!(state, &format!("Expected an array, but found: {}", v)); }, ) } } } -fn write_to_destination(context: &mut DvmContext, destination: &Location, value: DvmValue) { +fn write_to_destination(state: &mut DvmState, destination: &Location, value: DvmValue) { match destination { Location::Register(register) => { - context.registers[*register] = value; + state.registers[*register] = value; } Location::Stack { offset } => { - context.stack[*offset] = value; + state.stack[*offset] = value; } Location::Field { object_register, field_name, } => { - context.registers[*object_register] + state.registers[*object_register] .expect_object() .borrow_mut() .write_field(field_name, value); @@ -197,8 +209,8 @@ fn write_to_destination(context: &mut DvmContext, destination: &Location, value: index_register, offset, } => { - let index = compute_index_with_offset(&context.registers, *index_register, offset); - context.registers[*array_register] + let index = compute_index_with_offset(&state.registers, *index_register, offset); + state.registers[*array_register] .expect_array() .borrow_mut() .write_element(index, value); @@ -206,6 +218,32 @@ fn write_to_destination(context: &mut DvmContext, destination: &Location, value: } } +fn constant_array_to_array(constant_array: &DvmConstantArray) -> DvmArray { + match constant_array { + DvmConstantArray::Bytes(v) => DvmArray::Bytes(v.clone()), + DvmConstantArray::Ints(v) => DvmArray::Ints(v.clone()), + DvmConstantArray::Longs(v) => DvmArray::Longs(v.clone()), + DvmConstantArray::Doubles(v) => DvmArray::Doubles(v.clone()), + DvmConstantArray::USizes(v) => DvmArray::USizes(v.clone()), + DvmConstantArray::Booleans(v) => DvmArray::Booleans(v.clone()), + DvmConstantArray::Strings(vs) => { + DvmArray::Strings(vs.iter().map(|s| Rc::new(s.clone())).collect()) + } + DvmConstantArray::Arrays(va) => DvmArray::Arrays( + va.iter() + .map(|a| Rc::new(RefCell::new(constant_array_to_array(a)))) + .collect(), + ), + } +} + +fn constant_to_value(constant: &DvmConstant) -> DvmValue { + match constant { + DvmConstant::String(s) => DvmValue::String(Rc::new(s.clone())), + DvmConstant::Array(a) => DvmValue::Array(Rc::new(RefCell::new(constant_array_to_array(a)))), + } +} + fn immediate_to_value(immediate: &Immediate) -> DvmValue { match immediate { Immediate::Byte(b) => DvmValue::Byte(*b), @@ -214,135 +252,202 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue { Immediate::Double(d) => DvmValue::Double(*d), Immediate::Usize(s) => DvmValue::USize(*s), Immediate::Boolean(b) => DvmValue::Boolean(*b), - Immediate::ConstantPointer { - raw_pointer, - length, - } => DvmValue::ConstantPointer(DvmPointer { - raw_pointer: *raw_pointer, - length: *length, - }), + Immediate::Constant(c) => constant_to_value(c), Immediate::Empty => DvmValue::Empty, } } // TODO: find all possible unwraps/expects and wrap with call to dvm_panic -pub fn run(instructions: &[Instruction], context: &mut DvmContext) { +pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmContext) { let mut index = 0; while index < instructions.len() { - context.current_instruction = Some(instructions[index].clone()); + state.current_instruction = Some(instructions[index].clone()); index += 1; + use Instruction::*; match &instructions[index] { - Instruction::MoveImmediate { + MoveImmediate { destination, immediate, } => { - write_to_destination(context, destination, immediate_to_value(immediate)); + write_to_destination(state, destination, immediate_to_value(immediate)); } - Instruction::Copy { + Copy { source, destination, } => { - let value = copy_from_source(context, source); - write_to_destination(context, destination, value); + let value = copy_from_source(state, source); + write_to_destination(state, destination, value); } - Instruction::Push { source_register } => { - context - .stack - .push(context.registers[*source_register].clone()); + Push { source_register } => { + state.stack.push(state.registers[*source_register].clone()); } - Instruction::Pop { + Pop { destination_register, } => { - let value = context.stack.pop().expect("Stack underflow"); - context.registers[*destination_register] = value; + let value = state.stack.pop().unwrap_or_else(|| { + dvm_panic!(state, "Stack underflow"); + }); + state.registers[*destination_register] = value; } - Instruction::AllocateObject { + AllocateObject { implementation_name, destination_register, } => { let implementation = context .implementations .get(implementation_name.as_str()) - .unwrap(); - let object = DvmObject::new(implementation.clone()); - context.registers[*destination_register] = + .unwrap_or_else(|| { + dvm_panic!( + state, + &format!("Cannot find implementation {}", implementation_name) + ); + }) + .clone(); + let object = DvmObject::new(implementation); + state.registers[*destination_register] = DvmValue::Object(Rc::new(RefCell::new(object))); } - Instruction::InvokeStatic { + InvokeStatic { function_name, source_code_location, } => { + // Find function let static_function = context .static_functions .get(function_name.as_str()) - .unwrap() + .unwrap_or_else(|| { + dvm_panic!( + state, + &format!("Cannot find static function {}", function_name) + ); + }) .clone(); - push_call_frame(function_name.clone(), source_code_location.clone(), context); - run(static_function.instructions(), context); - pop_call_frame(context); + + // Do call + state.stack.push(DvmValue::Empty); // space for return value + push_call_frame(function_name.clone(), source_code_location.clone(), state); + run(static_function.instructions(), state, context); + pop_call_frame(state); } - Instruction::InvokeObject { + InvokeObject { object_register, function_name, source_code_location, } => { - let object = context.registers[*object_register].expect_object(); - let object_ref = object.borrow(); + // Find method and get instructions + let object_value = state.registers[*object_register].clone(); + let object_rc = object_value.expect_object_or_else(|v| { + dvm_panic!( + state, + &format!("Expected DvmValue::Object, but found {}", object_value) + ); + }); + let object_ref = object_rc.borrow(); let method = object_ref .get_method(function_name.as_str()) - .expect(&format!( - "Cannot find method {} for object {:?}", - function_name, object - )); + .unwrap_or_else(|| { + dvm_panic!( + state, + &format!( + "Cannot find method {} for object {:?}", + function_name, object_ref + ) + ); + }); let function = method.dm_fn(); let instructions = function.instructions(); - push_call_frame(function_name.clone(), source_code_location.clone(), context); - run(instructions, context); - pop_call_frame(context); + + // Do call + state.stack.push(DvmValue::Empty); // space for return value + state.stack.push(object_value); // self object + push_call_frame(function_name.clone(), source_code_location.clone(), state); + run(instructions, state, context); + pop_call_frame(state); + state.stack.pop(); // self object } - Instruction::PlatformCall { - platform_function_name, + InvokeStaticPlatform { + function_name, source_code_location, } => { + // Find function let platform_function = context .platform_functions - .get(platform_function_name.as_str()) - .unwrap() - .clone(); - push_call_frame( - platform_function_name.clone(), - source_code_location.clone(), - context, - ); - platform_function(context); - pop_call_frame(context); + .get(function_name.as_str()) + .unwrap_or_else(|| { + dvm_panic!( + state, + &format!("Cannot find static platform function {}", function_name) + ); + }); + + // Do call + state.stack.push(DvmValue::Empty); // space for return value + push_call_frame(function_name.clone(), source_code_location.clone(), state); + platform_function(state, context); + pop_call_frame(state); } - Instruction::Add { .. } => {} - Instruction::Subtract { .. } => {} - Instruction::Multiply { .. } => {} - Instruction::Divide { .. } => {} - Instruction::Modulo { .. } => {} - Instruction::Power { .. } => {} - Instruction::Jump { offset } => { + InvokeObjectPlatform { + object_register, + function_name, + source_code_location, + } => { + // Find function + let object_platform_function = context + .platform_functions + .get(function_name.as_str()) + .unwrap_or_else(|| { + dvm_panic!( + state, + &format!("Cannot find object platform function {}", function_name) + ); + }); + + // Get self object + let object_value = state.registers[*object_register].clone(); + if !object_value.is_object() { + dvm_panic!( + state, + &format!( + "Expected DvmValue::Object, but found DvmValue::{:?}", + object_value + ) + ); + } + + // Do call + state.stack.push(DvmValue::Empty); // space for return value + state.stack.push(object_value); // self object + push_call_frame(function_name.clone(), source_code_location.clone(), state); + object_platform_function(state, context); + pop_call_frame(state); + state.stack.pop(); // self object + } + Add { .. } => {} + Subtract { .. } => {} + Multiply { .. } => {} + Divide { .. } => {} + Modulo { .. } => {} + Power { .. } => {} + Jump { offset } => { update_index(&mut index, *offset); } - Instruction::JumpEqual { + JumpEqual { left_register, right_register, offset, } => { - let left_value = &context.registers[*left_register]; - let right_value = &context.registers[*right_register]; + let left_value = &state.registers[*left_register]; + let right_value = &state.registers[*right_register]; if left_value == right_value { update_index(&mut index, *offset); } } - Instruction::JumpNotEqual { .. } => {} - Instruction::JumpLessThan { .. } => {} - Instruction::JumpGreaterThan { .. } => {} - Instruction::JumpLessThanEqual { .. } => {} - Instruction::JumpGreaterThanEqual { .. } => {} - Instruction::Return => { + JumpNotEqual { .. } => {} + JumpLessThan { .. } => {} + JumpGreaterThan { .. } => {} + JumpLessThanEqual { .. } => {} + JumpGreaterThanEqual { .. } => {} + Return => { break; } } diff --git a/src/vm/platform/std_lib/core.rs b/src/vm/platform/std_lib/core.rs index 04e9aa9..60f7339 100644 --- a/src/vm/platform/std_lib/core.rs +++ b/src/vm/platform/std_lib/core.rs @@ -1,6 +1,6 @@ use crate::vm::object::DvmObject; use crate::vm::value::DvmValue; -use crate::vm::DvmContext; +use crate::vm::{DvmContext, DvmState}; use std::cell::RefCell; use std::rc::Rc; @@ -8,12 +8,12 @@ use std::rc::Rc; /// // Signature /// print(m: &(Byte | Int | Long | Double | USize | Boolean | Object | Empty)) /// ``` -pub fn dm_print(context: &mut DvmContext) { - print!("{}", get_string(context.pop_stack())); +pub fn dm_print(state: &mut DvmState, context: &DvmContext) { + print!("{}", get_string(state.pop_stack())); } -pub fn dm_println(context: &mut DvmContext) { - println!("{}", get_string(context.pop_stack())); +pub fn dm_println(state: &mut DvmState, context: &DvmContext) { + println!("{}", get_string(state.pop_stack())); } fn get_string(dvm_value: DvmValue) -> String { @@ -26,29 +26,11 @@ fn get_string(dvm_value: DvmValue) -> String { DvmValue::Object(object) => object_to_string(object.clone()), DvmValue::USize(u) => u.to_string(), DvmValue::Array(a) => a.borrow().to_string(), - DvmValue::ConstantPointer(p) => p.to_string(), + DvmValue::String(s) => s.to_string(), DvmValue::Empty => String::from("Empty"), } } fn object_to_string(object: Rc>) -> String { - if object.borrow().implementation().fqn() == "std::core::StringImpl" { - extract_string_from_string(object.clone()) - } else { - todo!("what happens if we don't have a String?") - } -} - -fn extract_string_from_string(string_object: Rc>) -> String { - let object_ref = string_object.borrow(); - let bytes_field_value = object_ref.read_field("bytes"); - if let DvmValue::ConstantPointer(bytes_ptr) = bytes_field_value { - let mut v = Vec::new(); - for i in 0..bytes_ptr.length { - v.push(unsafe { bytes_ptr.raw_pointer.add(i).read() }); - } - String::from_utf8(v).unwrap() - } else { - panic!("StringImpl.bytes field is not a DvmValue::ConstantPointer."); - } + todo!("Lookup to_string method!") } diff --git a/src/vm/value.rs b/src/vm/value.rs index e3f6723..223e0f8 100644 --- a/src/vm/value.rs +++ b/src/vm/value.rs @@ -21,8 +21,8 @@ pub enum DvmValue { // Array Array(Rc>), - // Pointer to constant u8 - ConstantPointer(DvmPointer), + // String + String(Rc), // Null Empty, @@ -45,7 +45,7 @@ impl Display for DvmValue { DvmValue::Boolean(b) => write!(f, "Boolean({})", b), DvmValue::Object(o) => write!(f, "Object({:p})", &o), DvmValue::Array(a) => write!(f, "Array({:p})", &a), - DvmValue::ConstantPointer(p) => write!(f, "ConstantPointer({})", p), + DvmValue::String(s) => write!(f, "String({})", s), DvmValue::Empty => write!(f, "Empty"), } } @@ -102,6 +102,14 @@ impl DvmValue { panic!("Expected DvmValue::Object, but found DvmValue::{:?}", self); } } + + pub fn expect_object_or_else(&self, f: impl FnOnce(&Self) -> DvmObject) -> Rc> { + if let DvmValue::Object(o) = self { + o.clone() + } else { + Rc::new(RefCell::new(f(self))) + } + } pub fn map_object( &self, @@ -182,15 +190,20 @@ impl DvmValue { panic!("Expected DvmValue::Boolean, but found DvmValue::{:?}", self); } } - - pub fn expect_constant_pointer(&self) -> DvmPointer { - if let DvmValue::ConstantPointer(ptr) = self { - ptr.clone() + + pub fn expect_string(&self) -> Rc { + if let DvmValue::String(s) = self { + s.clone() } else { - panic!( - "Expected DvmValue::ConstantPointer, but found DvmValue::{:?}", - self - ); + panic!("Expected DvmValue::String, but found DvmValue::{:?}", self); + } + } + + pub fn expect_string_or_else(&self, f: impl FnOnce(&Self) -> String) -> Rc { + if let DvmValue::String(s) = self { + s.clone() + } else { + Rc::new(f(self)) } } }