diff --git a/src/bin/dvm/main.rs b/src/bin/dvm/main.rs index d6bc6bb..8f566dc 100644 --- a/src/bin/dvm/main.rs +++ b/src/bin/dvm/main.rs @@ -1,10 +1,14 @@ -use deimos::vm::dm_type::DmType; +use deimos::vm::field::DvmField; +use deimos::vm::function::DvmFunction; +use deimos::vm::interface::DmInterface; use deimos::vm::lib::{DmConstant, DmLib}; -use deimos::vm::object_type::{DmField, DmFn, DmImplementation, DmInterface, DmMethod}; +use deimos::vm::method::DvmMethod; +use deimos::vm::object_type::DvmImplementation; use deimos::vm::op_codes::{ add_alloc, add_dealloc, add_invoke_fn, add_mov_const, add_platform_call, add_store, }; use deimos::vm::platform::init_platform_functions; +use deimos::vm::r#type::DvmType; use deimos::vm::{call_fn, DvmContext, DvmState}; use std::rc::Rc; @@ -13,12 +17,12 @@ fn main() { // - write a single lib with a main() // - call the main fn // fn main() { println "Hello, World!" } - + // std/core/array lib let mut array_lib = DmLib::new("std/core/array"); // std::core::Array - let array_int = DmInterface::new("std::core::Array", "Array"); + let array_int = DmInterface::new("std::core::Array"); array_lib.add_interface(array_int); let array_int_rc = array_lib .interfaces() @@ -27,15 +31,11 @@ fn main() { .unwrap(); // std::core::ArrayImpl - let mut array_impl = DmImplementation::new( - "std::core::ArrayImpl", - "ArrayImpl", - Some(array_int_rc.clone()), - ); + let mut array_impl = DvmImplementation::new("std::core::ArrayImpl", Some(array_int_rc.clone())); - let array_impl_ptr_address_fld = DmField::new("ptr_address", DmType::USize); - let array_impl_ptr_size_fld = DmField::new("ptr_size", DmType::USize); - let array_impl_length_fld = DmField::new("length", DmType::Long); + let array_impl_ptr_address_fld = DvmField::new("ptr_address", DvmType::USize); + let array_impl_ptr_size_fld = DvmField::new("ptr_size", DvmType::USize); + let array_impl_length_fld = DvmField::new("length", DvmType::Long); array_impl.add_field(array_impl_ptr_address_fld); array_impl.add_field(array_impl_ptr_size_fld); @@ -53,14 +53,14 @@ fn main() { add_store(&mut array_impl_ctor_0_bytecode, 0, 1, 2); add_store(&mut array_impl_ctor_0_bytecode, 0, 2, 3); - let array_impl_ctor_0_fn = DmFn::new( + let array_impl_ctor_0_fn = DvmFunction::new( "std::core::ArrayImpl::_ctor_0", "_ctor_0", array_impl_ctor_0_bytecode, 4, None, ); - let array_impl_ctor_0_method = DmMethod::new(array_impl_ctor_0_fn, None); + let array_impl_ctor_0_method = DvmMethod::new(array_impl_ctor_0_fn, None); array_impl.add_method(array_impl_ctor_0_method); array_lib.add_implementation(array_impl); @@ -68,7 +68,7 @@ fn main() { // std::core::String let mut string_lib = DmLib::new("std/core/string"); - let string_int = DmInterface::new("std::core::String", "String"); + let string_int = DmInterface::new("std::core::String"); string_lib.add_interface(string_int); let string_int_rc = string_lib .interfaces() @@ -76,13 +76,10 @@ fn main() { .find(|interface| interface.fqn() == "std::core::String") .unwrap(); - let mut string_impl = DmImplementation::new( - "std::core::StringImpl", - "StringImpl", - Some(string_int_rc.clone()), - ); + let mut string_impl = + DvmImplementation::new("std::core::StringImpl", Some(string_int_rc.clone())); - let bytes_field = DmField::new("bytes", DmType::Object); + let bytes_field = DvmField::new("bytes", DvmType::Object); string_impl.add_field(bytes_field); // std::core::String::_ctor_0( @@ -92,7 +89,7 @@ fn main() { let mut string_ctor_0_bytecode: Vec = Vec::new(); add_store(&mut string_ctor_0_bytecode, 0, 0, 1); - let string_ctor_0_fn = DmFn::new( + let string_ctor_0_fn = DvmFunction::new( "std::core::StringImpl::_ctor_0", "_ctor_0", string_ctor_0_bytecode, @@ -100,7 +97,7 @@ fn main() { None, ); - let string_ctor_0_method = DmMethod::new(string_ctor_0_fn, None); + let string_ctor_0_method = DvmMethod::new(string_ctor_0_fn, None); string_impl.add_method(string_ctor_0_method); @@ -148,7 +145,7 @@ fn main() { // Dealloc ArrayImpl add_dealloc(&mut main_byte_code, 2); - let main_dm_fn = DmFn::new("main", "main", main_byte_code, 7, None); + let main_dm_fn = DvmFunction::new("main", "main", main_byte_code, 7, None); greeting_lib.add_function(main_dm_fn); diff --git a/src/vm/array.rs b/src/vm/array.rs new file mode 100644 index 0000000..b397031 --- /dev/null +++ b/src/vm/array.rs @@ -0,0 +1,131 @@ +use crate::vm::object::DvmObject; +use crate::vm::pointer::DvmPointer; +use crate::vm::value::DvmValue; +use std::cell::RefCell; +use std::fmt::{Display, Write}; +use std::rc::Rc; +use std::slice::Iter; + +#[derive(Debug, PartialEq)] +pub enum DvmArray { + Bytes(Vec), + Ints(Vec), + Longs(Vec), + Doubles(Vec), + USizes(Vec), + Booleans(Vec), + Objects(Vec>>), + Arrays(Vec>>), + ConstantPointers(Vec), +} + +impl DvmArray { + pub fn read_element(&self, index: usize) -> DvmValue { + match self { + DvmArray::Bytes(vec) => DvmValue::Byte(vec[index]), + DvmArray::Ints(vec) => DvmValue::Int(vec[index]), + DvmArray::Longs(vec) => DvmValue::Long(vec[index]), + DvmArray::Doubles(vec) => DvmValue::Double(vec[index]), + DvmArray::USizes(vec) => DvmValue::USize(vec[index]), + 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()), + } + } + + pub fn write_element(&mut self, index: usize, value: DvmValue) { + match self { + DvmArray::Bytes(vec) => { + vec[index] = value.expect_byte(); + } + DvmArray::Ints(vec) => { + vec[index] = value.expect_int(); + } + DvmArray::Longs(vec) => { + vec[index] = value.expect_long(); + } + DvmArray::Doubles(vec) => { + vec[index] = value.expect_double(); + } + DvmArray::USizes(vec) => { + vec[index] = value.expect_usize(); + } + DvmArray::Booleans(vec) => { + vec[index] = value.expect_boolean(); + } + DvmArray::Objects(vec) => { + vec[index] = value.expect_object(); + } + DvmArray::Arrays(vec) => { + vec[index] = value.expect_array(); + } + DvmArray::ConstantPointers(vec) => { + vec[index] = value.expect_constant_pointer(); + } + } + } +} + +impl Display for DvmArray { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "[{}]", + self.into_iter() + .map(|v| v.to_string()) + .collect::>() + .join(", ") + ) + } +} + +pub enum DvmArrayIter<'a> { + Bytes(Iter<'a, u8>), + Ints(Iter<'a, i32>), + Longs(Iter<'a, i64>), + Doubles(Iter<'a, f64>), + USizes(Iter<'a, usize>), + Booleans(Iter<'a, bool>), + Objects(Iter<'a, Rc>>), + Arrays(Iter<'a, Rc>>), + ConstantPointers(Iter<'a, DvmPointer>), +} + +impl<'a> Iterator for DvmArrayIter<'a> { + type Item = DvmValue; + fn next(&mut self) -> Option { + match self { + DvmArrayIter::Bytes(iter) => iter.next().map(|b| DvmValue::Byte(*b)), + DvmArrayIter::Ints(iter) => iter.next().map(|i| DvmValue::Int(*i)), + DvmArrayIter::Longs(iter) => iter.next().map(|l| DvmValue::Long(*l)), + DvmArrayIter::Doubles(iter) => iter.next().map(|d| DvmValue::Double(*d)), + DvmArrayIter::USizes(iter) => iter.next().map(|u| DvmValue::USize(*u)), + 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())) + } + } + } +} + +impl<'a> IntoIterator for &'a DvmArray { + type Item = DvmValue; + type IntoIter = DvmArrayIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + match self { + DvmArray::Bytes(v) => DvmArrayIter::Bytes(v.iter()), + DvmArray::Ints(v) => DvmArrayIter::Ints(v.iter()), + DvmArray::Longs(v) => DvmArrayIter::Longs(v.iter()), + DvmArray::Doubles(v) => DvmArrayIter::Doubles(v.iter()), + DvmArray::USizes(v) => DvmArrayIter::USizes(v.iter()), + 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()), + } + } +} diff --git a/src/vm/dm_type.rs b/src/vm/dm_type.rs deleted file mode 100644 index d88a726..0000000 --- a/src/vm/dm_type.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[derive(Debug, PartialEq, Eq)] -pub enum DmType { - Byte, - Int, - Long, - Double, - Boolean, - Object, - USize, -} diff --git a/src/vm/dvm_value.rs b/src/vm/dvm_value.rs deleted file mode 100644 index a789828..0000000 --- a/src/vm/dvm_value.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::vm::object::DvmObject; -use std::rc::Rc; - -#[derive(Debug, PartialEq, Clone)] -pub enum DvmValue { - Byte(u8), - Int(i32), - Long(i64), - Double(f64), - Boolean(bool), - Object(Rc), - USize(usize), - Uninit, - Void, -} - -impl DvmValue { - pub fn from_object(object: DvmObject) -> Self { - DvmValue::Object(Rc::new(object)) - } - - pub fn expect_long(&self) -> i64 { - if let DvmValue::Long(l) = self { - *l - } else { - panic!("Expected DvmValue::Long, but found DvmValue::{:?}", self) - } - } - - pub fn is_long(&self) -> bool { - match self { - DvmValue::Long(_) => true, - _ => false, - } - } - - pub fn expect_object(&self) -> Rc { - if let DvmValue::Object(o) = self { - o.clone() - } else { - panic!("Expected DvmValue::Object, but found DvmValue::{:?}", self); - } - } - - pub fn is_object(&self) -> bool { - match self { - DvmValue::Object(_) => true, - _ => false, - } - } - - pub fn expect_usize(&self) -> usize { - if let DvmValue::USize(u) = self { - *u - } else { - panic!("Expected DvmValue::USize, but found DvmValue::{:?}", self); - } - } - - pub fn is_usize(&self) -> bool { - match self { - DvmValue::USize(_) => true, - _ => false, - } - } -} diff --git a/src/vm/field.rs b/src/vm/field.rs new file mode 100644 index 0000000..85ff757 --- /dev/null +++ b/src/vm/field.rs @@ -0,0 +1,36 @@ +use crate::vm::r#type::DvmType; + +#[derive(Debug, Eq)] +pub struct DvmField { + name: String, + dvm_type: DvmType, + index: usize, +} + +impl PartialEq for DvmField { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl DvmField { + pub fn new(name: &str, dvm_type: DvmType, index: usize) -> Self { + DvmField { + name: name.to_string(), + dvm_type, + index, + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn dvm_type(&self) -> &DvmType { + &self.dvm_type + } + + pub fn index(&self) -> usize { + self.index + } +} diff --git a/src/vm/function.rs b/src/vm/function.rs new file mode 100644 index 0000000..ad9e43c --- /dev/null +++ b/src/vm/function.rs @@ -0,0 +1,32 @@ +use crate::vm::instruction::Instruction; + +#[derive(Debug)] +pub struct DvmFunction { + fqn: String, + instructions: Vec, +} + +impl DvmFunction { + pub fn new(fqn: &str, instructions: &[Instruction]) -> Self { + DvmFunction { + fqn: fqn.to_string(), + instructions: Vec::from(instructions), + } + } + + pub fn fqn(&self) -> &str { + self.fqn.as_str() + } + + pub fn instructions(&self) -> &Vec { + &self.instructions + } +} + +impl PartialEq for DvmFunction { + fn eq(&self, other: &Self) -> bool { + self.fqn == other.fqn + } +} + +impl Eq for DvmFunction {} diff --git a/src/vm/instruction.rs b/src/vm/instruction.rs new file mode 100644 index 0000000..8e42022 --- /dev/null +++ b/src/vm/instruction.rs @@ -0,0 +1,139 @@ +use std::rc::Rc; + +#[derive(Debug, Clone)] +pub enum Instruction { + MoveImmediate { + destination: Location, + immediate: Immediate, + }, + Copy { + source: Location, + destination: Location, + }, + Push { + source_register: usize, + }, + Pop { + destination_register: usize, + }, + AllocateObject { + implementation_name: Rc, + destination_register: usize, + }, + InvokeStatic { + function_name: Rc, + source_code_location: SourceCodeLocation, + }, + InvokeObject { + object_register: usize, + function_name: Rc, + source_code_location: SourceCodeLocation, + }, + PlatformCall { + platform_function_name: Rc, + source_code_location: SourceCodeLocation, + }, + Add { + left: u8, + right: u8, + destination: u8, + }, + Subtract { + left: u8, + right: u8, + destination: u8, + }, + Multiply { + left: u8, + right: u8, + destination: u8, + }, + Divide { + left: u8, + right: u8, + destination: u8, + }, + Modulo { + left: u8, + right: u8, + destination: u8, + }, + Power { + left: u8, + right: u8, + destination: u8, + }, + Jump { + offset: isize, + }, + JumpEqual { + left_register: usize, + right_register: usize, + offset: isize, + }, + JumpNotEqual { + left_register: usize, + right_register: usize, + offset: isize, + }, + JumpLessThan { + left_register: usize, + right_register: usize, + offset: isize, + }, + JumpGreaterThan { + left_register: usize, + right_register: usize, + offset: isize, + }, + JumpLessThanEqual { + left_register: usize, + right_register: usize, + offset: isize, + }, + JumpGreaterThanEqual { + left_register: usize, + right_register: usize, + offset: isize, + }, + Return, +} + +#[derive(Debug, Clone)] +pub enum Immediate { + Byte(u8), + Int(i32), + Long(i64), + Double(f64), + Usize(usize), + Boolean(bool), + ConstantPointer { + raw_pointer: *const u8, + length: usize + }, + Empty, +} + +#[derive(Debug, Clone)] +pub enum Location { + Register(usize), + Stack { + offset: usize, + }, + Field { + object_register: usize, + field_name: Rc, + }, + Array { + array_register: usize, + index_register: usize, + offset: Option, + }, +} + +#[derive(Debug, Clone)] +pub struct SourceCodeLocation { + pub source_file_name: String, + pub line: i64, + pub char: i64, +} diff --git a/src/vm/interface.rs b/src/vm/interface.rs new file mode 100644 index 0000000..a4daf69 --- /dev/null +++ b/src/vm/interface.rs @@ -0,0 +1,46 @@ +use crate::vm::function::DvmFunction; +use crate::vm::virtual_method::DmVirtualMethod; +use std::rc::Rc; + +#[derive(Debug, Eq)] +pub struct DmInterface { + fqn: String, + static_functions: Vec>, + virtual_methods: Vec, +} + +impl PartialEq for DmInterface { + fn eq(&self, other: &Self) -> bool { + self.fqn == other.fqn + } +} + +impl DmInterface { + pub fn new(fqn: &str) -> Self { + DmInterface { + fqn: fqn.to_string(), + static_functions: Vec::new(), + virtual_methods: Vec::new(), + } + } + + pub fn fqn(&self) -> &str { + self.fqn.as_str() + } + + pub fn add_function(&mut self, dm_fn: DvmFunction) { + self.static_functions.push(Rc::new(dm_fn)); + } + + pub fn functions(&self) -> &Vec> { + &self.static_functions + } + + pub fn add_method(&mut self, dm_virtual_method: DmVirtualMethod) { + self.virtual_methods.push(dm_virtual_method); + } + + pub fn virtual_methods(&self) -> &Vec { + &self.virtual_methods + } +} diff --git a/src/vm/lib/mod.rs b/src/vm/lib/mod.rs index 560d4f5..709c01a 100644 --- a/src/vm/lib/mod.rs +++ b/src/vm/lib/mod.rs @@ -3,15 +3,17 @@ mod magic; mod symbol; mod write; -use crate::vm::object_type::{DmFn, DmImplementation, DmInterface}; +use crate::vm::function::DvmFunction; +use crate::vm::interface::DmInterface; +use crate::vm::object_type::DvmImplementation; use std::rc::Rc; pub struct DmLib { name: String, constants: Vec, interfaces: Vec>, - implementations: Vec>, - functions: Vec>, + implementations: Vec>, + functions: Vec>, } impl DmLib { @@ -45,19 +47,19 @@ impl DmLib { self.interfaces.push(Rc::new(interface)); } - pub fn implementations(&self) -> &Vec> { + pub fn implementations(&self) -> &Vec> { &self.implementations } - pub fn add_implementation(&mut self, implementation: DmImplementation) { + pub fn add_implementation(&mut self, implementation: DvmImplementation) { self.implementations.push(Rc::new(implementation)); } - pub fn functions(&self) -> &Vec> { + pub fn functions(&self) -> &Vec> { &self.functions } - pub fn add_function(&mut self, function: DmFn) { + pub fn add_function(&mut self, function: DvmFunction) { self.functions.push(Rc::new(function)); } } diff --git a/src/vm/mem.rs b/src/vm/mem.rs deleted file mode 100644 index 36143b3..0000000 --- a/src/vm/mem.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::vm::dm_type::DmType; -use crate::vm::dvm_value::DvmValue; -use crate::vm::object::DvmObject; -use std::rc::Rc; - -unsafe fn read_field(data_pointer: *const u8, dm_type: &DmType) -> DvmValue { - match dm_type { - DmType::Byte => DvmValue::Byte(data_pointer.read()), - DmType::Int => DvmValue::Int(data_pointer.cast::().read()), - DmType::Long => DvmValue::Long(data_pointer.cast::().read()), - DmType::USize => DvmValue::USize(data_pointer.cast::().read()), - DmType::Double => DvmValue::Double(data_pointer.cast::().read()), - DmType::Boolean => DvmValue::Boolean(data_pointer.cast::().read()), - DmType::Object => DvmValue::Object(data_pointer.cast::>().read()), - } -} - -pub fn read_field_by_name(field_name: &str, self_object: &DvmObject) -> DvmValue { - let (field_index, field) = self_object - .implementation() - .fields() - .iter() - .enumerate() - .find(|(_index, field)| field.name() == field_name) - .expect(&format!( - "Cannot find field {} in {}", - field_name, - self_object.implementation().fqn() - )); - let data_pointer = self_object.data()[field_index]; - unsafe { read_field(data_pointer, field.dm_type()) } -} - -pub fn read_field_by_index(index: usize, self_object: &DvmObject) -> DvmValue { - let field = &self_object.implementation().fields()[index]; - let data_pointer = self_object.data()[index]; - unsafe { read_field(data_pointer, field.dm_type()) } -} - -unsafe fn write_field(data_pointer: *mut u8, value: DvmValue) { - match value { - DvmValue::Byte(b) => { - data_pointer.write(b); - } - DvmValue::Int(i) => { - data_pointer.cast::().write(i); - } - DvmValue::Long(l) => { - data_pointer.cast::().write(l); - } - DvmValue::USize(u) => { - data_pointer.cast::().write(u); - } - DvmValue::Double(d) => { - data_pointer.cast::().write(d); - } - DvmValue::Boolean(b) => { - data_pointer.cast::().write(b); - } - DvmValue::Object(o) => { - data_pointer.cast::>().write(o); - } - DvmValue::Uninit => panic!("Cannot write DvmValue::Uninit to field."), - DvmValue::Void => panic!("Cannot write DvmValue::Void to field."), - } -} - -pub fn write_field_by_name(field_name: &str, self_object: &DvmObject, value: DvmValue) { - let field_index = self_object - .implementation() - .fields() - .iter() - .position(|field| field.name() == field_name) - .expect(&format!( - "Cannot find field {} in {}", - field_name, - self_object.implementation().fqn() - )); - let data_pointer = self_object.data()[field_index]; - unsafe { write_field(data_pointer, value) }; -} - -pub fn write_field_by_index(index: usize, self_object: &DvmObject, value: DvmValue) { - let data_pointer = self_object.data()[index]; - unsafe { write_field(data_pointer, value) }; -} diff --git a/src/vm/method.rs b/src/vm/method.rs new file mode 100644 index 0000000..6b7a67e --- /dev/null +++ b/src/vm/method.rs @@ -0,0 +1,32 @@ +use crate::vm::function::DvmFunction; +use crate::vm::virtual_method::DmVirtualMethod; +use std::rc::Rc; + +#[derive(Debug, Eq)] +pub struct DvmMethod { + function: Rc, + implements: Option>, +} + +impl PartialEq for DvmMethod { + fn eq(&self, other: &Self) -> bool { + self.function == other.function + } +} + +impl DvmMethod { + pub fn new(dm_fn: DvmFunction, implements: Option>) -> Self { + DvmMethod { + function: Rc::new(dm_fn), + implements, + } + } + + pub fn fqn(&self) -> &str { + self.function.fqn() + } + + pub fn dm_fn(&self) -> Rc { + self.function.clone() + } +} diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 6233e00..b622b2f 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,556 +1,350 @@ -pub mod dm_type; -pub mod dvm_value; +mod array; +mod field; +mod function; +mod instruction; +mod interface; pub mod lib; -pub mod mem; +mod method; pub mod object; pub mod object_type; pub mod op_codes; pub mod platform; +mod pointer; +pub mod r#type; pub mod util; +pub mod value; +mod virtual_method; -use crate::vm::dvm_value::DvmValue; -use crate::vm::lib::{DmConstant, DmLib}; -use crate::vm::mem::{read_field_by_index, write_field_by_index}; +use crate::vm::instruction::{Immediate, Instruction, Location, SourceCodeLocation}; use crate::vm::object::DvmObject; -use crate::vm::object_type::DmFn; -use op_codes::*; -use std::alloc::{alloc, dealloc, Layout}; +use crate::vm::object_type::DvmImplementation; +use crate::vm::pointer::DvmPointer; +use crate::vm::value::DvmValue; +use function::DvmFunction; +use std::cell::RefCell; use std::collections::HashMap; +use std::fmt::Display; use std::rc::Rc; -pub type PlatformFunction = - fn(args: Vec, state: &mut DvmState, context: &DvmContext) -> DvmValue; - -#[derive(Debug)] -enum CallFrame { - PlatformCall(CallFrameInfo), - DeimosCall(CallFrameInfo), +fn dvm_panic(context: &DvmContext, message: &str) { + println!("----"); + println!("Deimos Virtual Machine: Panic!"); + println!("{}", message); + println!("----"); + println!("Current Instruction: {:?}", context.current_instruction); + println!("Registers:"); + for (i, register) in context.registers.iter().enumerate() { + println!("\tr{}: {:?}", i, register); + } + println!("Call stack:"); + for call in context.call_stack.iter() { + println!("\t{}", call); + } + println!("Stack:"); + for (i, value) in context.stack.iter().enumerate() { + println!("\t{}: {}", i, value); + } + println!("----"); } -#[derive(Debug)] -struct CallFrameInfo { - pub fqn: String, +macro_rules! dvm_panic { + ($context: expr, $message: expr) => { + dvm_panic($context, $message); + panic!() + }; } +pub type PlatformFunction = fn(context: &mut DvmContext); + pub struct DvmContext { - libs: Vec>, - function_cache: HashMap>, + call_stack: Vec, + current_instruction: Option, + registers: Vec, + stack: Vec, + implementations: HashMap>, + static_functions: HashMap>, platform_functions: HashMap, } impl DvmContext { pub fn new() -> Self { DvmContext { - libs: Vec::new(), - function_cache: HashMap::new(), + call_stack: vec![], + current_instruction: None, + registers: vec![], + stack: vec![], + implementations: HashMap::new(), + static_functions: HashMap::new(), platform_functions: HashMap::new(), } } - pub fn load_libs(&mut self, libs: Vec>) { - for lib in libs { - for lib_fn in lib.functions() { - self.function_cache - .insert(lib_fn.fqn().to_string(), lib_fn.clone()); - } - for interface_function in lib - .interfaces() - .iter() - .flat_map(|interface| interface.functions()) - { - self.function_cache.insert( - interface_function.fqn().to_string(), - interface_function.clone(), - ); - } - for implementation_function in lib - .implementations() - .iter() - .flat_map(|implementation| implementation.functions()) - { - self.function_cache.insert( - implementation_function.fqn().to_string(), - implementation_function.clone(), - ); - } - for method in lib - .implementations() - .iter() - .flat_map(|implementation| implementation.methods()) - { - self.function_cache - .insert(method.dm_fn().fqn().to_string(), method.dm_fn()); - } - self.libs.push(lib); - } - } - - pub fn load_platform_fns(&mut self, platform_fns: HashMap) { - platform_fns.iter().for_each(|(fqn, platform_function)| { - self.platform_functions - .insert(fqn.to_string(), *platform_function); - }); - } - - pub fn fn_by_fqn(&self, fqn: &str) -> Option> { - self.function_cache.get(fqn).cloned() + pub fn pop_stack(&mut self) -> DvmValue { + self.stack.pop().unwrap_or_else(|| { + dvm_panic!(self, "Stack underflow!"); + }) } } -pub struct DvmState { - call_stack: Vec, - registers: Vec, - register_state_stack: Vec>, +pub struct DvmCall { + function_name: Rc, + source_code_location: SourceCodeLocation, } -impl DvmState { - pub fn new() -> Self { - DvmState { - call_stack: Vec::new(), - registers: Vec::new(), - register_state_stack: Vec::new(), - } +impl Display for DvmCall { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!( + "{} in {} @ {}:{}", + self.function_name, + self.source_code_location.source_file_name, + self.source_code_location.line, + self.source_code_location.char + )) } } -macro_rules! dump_state { - ( $state: expr ) => { - println!("Registers: "); - for (i, register) in $state.registers.iter().enumerate() { - println!(" r{}: {:?}", i, register); - } - - println!("Call stack:"); - for call_frame in &$state.call_stack { - match call_frame { - CallFrame::PlatformCall(frame_info) => { - println!(" {}", frame_info.fqn); - } - CallFrame::DeimosCall(frame_info) => { - println!(" {}", frame_info.fqn); - } - } - } - }; -} - -macro_rules! dvm_panic { - ( $message: expr, $state: expr ) => {{ - println!("----"); - println!("Dvm panic: {}", $message); - println!("----"); - dump_state!($state); - panic!(); - }}; -} - -pub fn call_fn( - state: &mut DvmState, - context: &DvmContext, - dm_fn: &DmFn, - args: Vec, -) -> DvmValue { - // save current state - state.call_stack.push(CallFrame::DeimosCall(CallFrameInfo { - fqn: dm_fn.fqn().to_string(), - })); - state.register_state_stack.push(state.registers.clone()); - - // zero registers and make sure there are enough for dm_function - state.registers.clear(); - if state.registers.len() < dm_fn.number_used_registers() { - state - .registers - .resize(dm_fn.number_used_registers(), DvmValue::Uninit); - } - - // push args - for (i, arg) in args.iter().enumerate() { - state.registers[i] = arg.clone(); - } - - // run the byte code - run_byte_code(state, context, &dm_fn.byte_code()); - - // restore state - state.registers = state.register_state_stack.pop().unwrap(); - state.call_stack.pop(); - - // get return value - if let Some(return_register) = dm_fn.return_register() { - state - .registers - .get(return_register as usize) - .map(|m| m.clone()) - .unwrap() +fn update_index(index: &mut usize, offset: isize) { + if offset.is_negative() { + *index -= offset.abs() as usize; } else { - DvmValue::Void + *index += offset as usize; } } -macro_rules! next_8 { - ( $byte_code: expr, $T: ident ) => { - $byte_code.next().unwrap() as $T - }; +fn push_call_frame( + function_name: Rc, + source_code_location: SourceCodeLocation, + context: &mut DvmContext, +) { + context.call_stack.push(DvmCall { + function_name, + source_code_location, + }); } -macro_rules! next_32_le { - ( $byte_code: expr, $T: ident ) => { - next_8!($byte_code, $T) - + (next_8!($byte_code, $T) << 8) - + (next_8!($byte_code, $T) << 16) - + (next_8!($byte_code, $T) << 24) - }; +fn pop_call_frame(context: &mut DvmContext) { + context.call_stack.pop(); } -macro_rules! next_64_le { - ( $byte_code: expr, $T: ident ) => { - next_8!($byte_code, $T) - + (next_8!($byte_code, $T) << 8) - + (next_8!($byte_code, $T) << 16) - + (next_8!($byte_code, $T) << 24) - + (next_8!($byte_code, $T) << 32) - + (next_8!($byte_code, $T) << 40) - + (next_8!($byte_code, $T) << 48) - + (next_8!($byte_code, $T) << 56) - }; -} - -macro_rules! next_usize_le { - ( $byte_code: expr ) => {{ - let mut u: usize = 0; - for i in 0..std::mem::size_of::() { - u += next_8!($byte_code, usize) << (8 * i); +fn compute_index_with_offset( + registers: &Vec, + index_register: usize, + offset: &Option, +) -> usize { + let index = registers[index_register].as_usize().expect(&format!( + "Could not convert the value of index_register {} to usize; found {:?}", + index_register, registers[index_register] + )); + if let Some(o) = offset { + if o.is_negative() { + index - o.unsigned_abs() + } else { + index + o.unsigned_abs() } - u - }}; + } else { + index + } } -macro_rules! read_array_u8 { - ( $iter: expr ) => {{ - let arr_length = next_8!($iter, u8); - let mut arr = Vec::with_capacity(arr_length as usize); - let mut i = 0; - while i < arr_length { - arr.push(next_8!($iter, u8)); - i += 1; +fn copy_from_source(context: &DvmContext, source: &Location) -> DvmValue { + match source { + Location::Register(register) => context.registers[*register].clone(), + Location::Stack { offset } => context.stack[*offset].clone(), + Location::Field { + object_register, + field_name, + } => context.registers[*object_register].map_object( + |o| o.borrow().read_field(field_name).clone(), + |v| { + dvm_panic!(context, &format!("Expected an object, but found: {}", v)); + }, + ), + Location::Array { + array_register, + index_register, + offset, + } => { + let index = compute_index_with_offset(&context.registers, *index_register, offset); + context.registers[*array_register].map_array( + |a| a.borrow().read_element(index), + |v| { + dvm_panic!(context, &format!("Expected an array, but found: {}", v)); + }, + ) } - arr - }}; + } } -macro_rules! read_string { - ( $iter: expr ) => {{ - let str_length = next_32_le!($iter, usize); - let mut str_raw: Vec = Vec::new(); - let mut i = 0; - while i < str_length { - str_raw.push($iter.next().unwrap()); - i += 1; +fn write_to_destination(context: &mut DvmContext, destination: &Location, value: DvmValue) { + match destination { + Location::Register(register) => { + context.registers[*register] = value; } - String::from_utf8(str_raw).unwrap() - }}; + Location::Stack { offset } => { + context.stack[*offset] = value; + } + Location::Field { + object_register, + field_name, + } => { + context.registers[*object_register] + .expect_object() + .borrow_mut() + .write_field(field_name, value); + } + Location::Array { + array_register, + index_register, + offset, + } => { + let index = compute_index_with_offset(&context.registers, *index_register, offset); + context.registers[*array_register] + .expect_array() + .borrow_mut() + .write_element(index, value); + } + } } -pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8]) { - let mut iter = byte_code.iter().cloned(); - while let Some(op_code) = iter.next() { - match op_code { - MOV_BYTE => { - todo!() - } - MOV_INT => { - let target_register = next_8!(iter, usize); - let operand = next_32_le!(iter, u32) as i32; - state.registers[target_register] = DvmValue::Int(operand); - } - MOV_LONG => { - let target_register = next_8!(iter, usize); - let operand = next_64_le!(iter, u64) as i64; - state.registers[target_register] = DvmValue::Long(operand); - } - MOV_DOUBLE => { - let target_register = next_8!(iter, usize); - let operand = next_64_le!(iter, u64) as f64; - state.registers[target_register] = DvmValue::Double(operand); - } - MOV_REGISTER => { - let target_register = next_8!(iter, usize); - let source_register = next_8!(iter, usize); - let source_value = - std::mem::replace(&mut state.registers[source_register], DvmValue::Uninit); - state.registers[target_register] = source_value; - } - LOAD => { - let target_register = next_8!(iter, usize); - let source_register = next_8!(iter, usize); - let source_object_field_index = next_usize_le!(iter); +fn immediate_to_value(immediate: &Immediate) -> DvmValue { + match immediate { + Immediate::Byte(b) => DvmValue::Byte(*b), + Immediate::Int(i) => DvmValue::Int(*i), + Immediate::Long(l) => DvmValue::Long(*l), + 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::Empty => DvmValue::Empty, + } +} - let source_object = state - .registers - .get(source_register) - .unwrap() - .expect_object(); - - state.registers[target_register] = - read_field_by_index(source_object_field_index, &source_object); +// TODO: find all possible unwraps/expects and wrap with call to dvm_panic +pub fn run(instructions: &[Instruction], context: &mut DvmContext) { + let mut index = 0; + while index < instructions.len() { + context.current_instruction = Some(instructions[index].clone()); + index += 1; + match &instructions[index] { + Instruction::MoveImmediate { + destination, + immediate, + } => { + write_to_destination(context, destination, immediate_to_value(immediate)); } - STORE => { - let target_register = next_8!(iter, usize); - let target_object_field_index = next_usize_le!(iter); - let source_register = next_8!(iter, usize); - - let target_object = state - .registers - .get(target_register) - .unwrap() - .expect_object(); - - let source_value = - std::mem::replace(&mut state.registers[source_register], DvmValue::Uninit); - write_field_by_index(target_object_field_index, &target_object, source_value); + Instruction::Copy { + source, + destination, + } => { + let value = copy_from_source(context, source); + write_to_destination(context, destination, value); } - ALLOC => { - let target_register = next_8!(iter, usize); - let impl_name = read_string!(iter); - + Instruction::Push { source_register } => { + context + .stack + .push(context.registers[*source_register].clone()); + } + Instruction::Pop { + destination_register, + } => { + let value = context.stack.pop().expect("Stack underflow"); + context.registers[*destination_register] = value; + } + Instruction::AllocateObject { + implementation_name, + destination_register, + } => { let implementation = context - .libs - .iter() - .find_map(|lib| { - lib.implementations() - .iter() - .find(|implementation| implementation.fqn() == impl_name) - }) - .unwrap_or_else(|| { - dvm_panic!(&format!("Implementation not found: {}", impl_name), state) - }) - .clone(); - - let dm_alloc_object = DvmObject::new(implementation); - state.registers[target_register] = DvmValue::from_object(dm_alloc_object); + .implementations + .get(implementation_name.as_str()) + .unwrap(); + let object = DvmObject::new(implementation.clone()); + context.registers[*destination_register] = + DvmValue::Object(Rc::new(RefCell::new(object))); } - DEALLOC => { - let target_register = next_8!(iter, usize); - let target_object = - std::mem::replace(&mut state.registers[target_register], DvmValue::Uninit) - .expect_object(); - drop(target_object); // explicit - state.registers[target_register] = DvmValue::Uninit; - } - MOV_CONST => { - // Decode - let address_register = next_8!(iter, usize); - let size_register = next_8!(iter, usize); - let lib_name = read_string!(iter); - let const_id = next_32_le!(iter, usize); - - // Get constant - let Some(lib) = context.libs.iter().find(|lib| lib.name() == lib_name) else { - dvm_panic!( - &format!("Could not find lib with name: {}", lib_name), - state - ); - }; - let constant = lib.constants().get(const_id).unwrap(); - let DmConstant::String(s) = constant; - let pointer = s.as_ptr(); - - // Store the pointer metadata in target registers. - state.registers[address_register] = DvmValue::USize(pointer as usize); - state.registers[size_register] = DvmValue::USize(s.len()); - } - ALLOC_RAW => { - // Allocates a raw number of bytes, with the number of bytes determined by the value - // of the source register. - let address_register = next_8!(iter, usize); - let source_register = next_8!(iter, usize); - let size = state.registers.get(source_register).unwrap().expect_long() as usize; - let layout = Layout::from_size_align(size, 1).unwrap(); - let raw_ptr = unsafe { alloc(layout) }; - state.registers[address_register] = DvmValue::USize(raw_ptr as usize); - } - DEALLOC_RAW => { - // Deallocates a DvmValue::Pointer(DvmPointer) in the target register. - let address_register = next_8!(iter, usize); - let size_register = next_8!(iter, usize); - let address = state - .registers - .get(address_register) + Instruction::InvokeStatic { + function_name, + source_code_location, + } => { + let static_function = context + .static_functions + .get(function_name.as_str()) .unwrap() - .expect_usize(); - let size = state.registers.get(size_register).unwrap().expect_usize(); - let layout = Layout::from_size_align(size, 1).unwrap(); - unsafe { - dealloc(address as *mut u8, layout); - } - state.registers[address_register] = DvmValue::Uninit; - state.registers[size_register] = DvmValue::Uninit; + .clone(); + push_call_frame(function_name.clone(), source_code_location.clone(), context); + run(static_function.instructions(), context); + pop_call_frame(context); } - PLATFORM_CALL => { - // Calls a platform function. The result of the platform call is stored in the - // specified return register. - let symbol_name = read_string!(iter); - let return_register = next_8!(iter, usize); - let arg_registers = read_array_u8!(iter); - - let mut args = Vec::with_capacity(arg_registers.len()); - for arg_register in arg_registers { - let value = state.registers.get(arg_register as usize).unwrap(); - args.push(value.clone()); - } - - let platform_function = context.platform_functions.get(&symbol_name).unwrap(); - state - .call_stack - .push(CallFrame::PlatformCall(CallFrameInfo { fqn: symbol_name })); - let call_result = platform_function(args, state, context); - state.registers[return_register] = call_result; - state.call_stack.pop(); + Instruction::InvokeObject { + object_register, + function_name, + source_code_location, + } => { + let object = context.registers[*object_register].expect_object(); + let object_ref = object.borrow(); + let method = object_ref + .get_method(function_name.as_str()) + .expect(&format!( + "Cannot find method {} for object {:?}", + function_name, object + )); + 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); } - INVOKE_FN => { - let symbol_name = read_string!(iter); - let return_register = next_8!(iter, usize); - let arg_registers = read_array_u8!(iter); - - let mut args = Vec::with_capacity(arg_registers.len()); - for arg_register in arg_registers { - let value = state.registers.get(arg_register as usize).unwrap(); - args.push(value.clone()); - } - - let dm_fn = context.function_cache.get(&symbol_name).unwrap(); - let call_result = call_fn(state, context, dm_fn, args); - state.registers[return_register] = call_result; - } - INVOKE_VIRTUAL => { - let symbol_name = read_string!(iter); - let return_register = next_8!(iter, usize); - let arg_registers = read_array_u8!(iter); - - let mut args = Vec::with_capacity(arg_registers.len()); - for arg_register in arg_registers { - let value = state.registers.get(arg_register as usize).unwrap(); - args.push(value.clone()); - } - - let self_obj = args.get(0).unwrap().expect_object(); - let method = self_obj - .implementation() - .find_method(&symbol_name, &self_obj) - .unwrap_or_else(|| { - dvm_panic!( - &format!("Could not find method with name: {}", symbol_name), - state - ); - }); - let dm_fn = method.dm_fn(); - - let call_result = call_fn(state, context, &dm_fn, args); - state.registers[return_register] = call_result; - } - INVOKE_DYNAMIC => { - unimplemented!("INVOKE_DYNAMIC is not yet supported and may never be.") - } - MULTIPLY => { - todo!() - } - op_code => { - dvm_panic!( - &format!("Unimplemented or unknown op code: {}", op_code), - state + Instruction::PlatformCall { + platform_function_name, + source_code_location, + } => { + 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); + } + Instruction::Add { .. } => {} + Instruction::Subtract { .. } => {} + Instruction::Multiply { .. } => {} + Instruction::Divide { .. } => {} + Instruction::Modulo { .. } => {} + Instruction::Power { .. } => {} + Instruction::Jump { offset } => { + update_index(&mut index, *offset); + } + Instruction::JumpEqual { + left_register, + right_register, + offset, + } => { + let left_value = &context.registers[*left_register]; + let right_value = &context.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 => { + break; } } } } - -#[cfg(test)] -mod run_code_tests { - use super::*; - use crate::vm::dm_type::DmType; - use crate::vm::object_type::{DmField, DmImplementation}; - - macro_rules! assert_register { - ( $expected: expr, $state: expr, $register_number: expr ) => { - assert_eq!($expected, $state.registers.remove($register_number)); - }; - } - - fn setup<'a>(number_of_registers: usize) -> (DvmState, DvmContext) { - let mut state = DvmState::new(); - state - .registers - .resize(number_of_registers, DvmValue::Uninit); - (state, DvmContext::new()) - } - - fn impl_with_object_field() -> DmImplementation { - let mut dm_impl = DmImplementation::new("ImplWithObjectField", "ImplWithObjectField", None); - let object_field = DmField::new("object_field", DmType::Object); - dm_impl.add_field(object_field); - dm_impl - } - - #[test] - fn mov_1_as_int() { - let mut code = Vec::new(); - add_mov_int(&mut code, 0, 1); - let (mut state, context) = setup(1); - run_byte_code(&mut state, &context, &code); - assert_register!(DvmValue::Int(1), state, 0); - } - - #[test] - fn move_65535_as_int() { - let mut code = Vec::new(); - add_mov_int(&mut code, 0, 0xffff); - let (mut state, context) = setup(1); - run_byte_code(&mut state, &context, &code); - assert_register!(DvmValue::Int(0xffff), state, 0); - } - - #[test] - fn move_int_max_as_int() { - let mut code = Vec::new(); - add_mov_int(&mut code, 0, 0x0fff_ffff); - let (mut state, context) = setup(1); - run_byte_code(&mut state, &context, &code); - assert_register!(DvmValue::Int(0x0fff_ffff), state, 0); - } - - #[test] - fn move_register() { - let mut code = Vec::new(); - add_mov_int(&mut code, 1, 1); - add_mov_register(&mut code, 0, 1); - let (mut state, context) = setup(2); - run_byte_code(&mut state, &context, &code); - assert_register!(DvmValue::Int(1), state, 0); - } - - #[test] - fn load_object() { - let dummy_impl = impl_with_object_field(); - let mut dummy_lib = DmLib::new("dummy"); - dummy_lib.add_implementation(dummy_impl); - let dummy_impl_ref = dummy_lib - .implementations() - .iter() - .find(|implementation| implementation.fqn() == "dummy") - .unwrap(); - - let mut code = Vec::new(); - add_alloc(&mut code, 0, dummy_impl_ref.fqn()); - add_alloc(&mut code, 1, dummy_impl_ref.fqn()); - add_store(&mut code, 0, 0, 1); - add_load(&mut code, 2, 0, 0); - - let (mut state, mut context) = setup(3); - state.registers.resize(3, DvmValue::Uninit); - context.load_libs(vec![Rc::new(dummy_lib)]); - run_byte_code(&mut state, &context, &code); - - assert!(state.registers[2].is_object()) - } -} diff --git a/src/vm/object.rs b/src/vm/object.rs index 9951be3..b8e8061 100644 --- a/src/vm/object.rs +++ b/src/vm/object.rs @@ -1,52 +1,52 @@ -use crate::vm::dm_type::DmType; -use crate::vm::object_type::DmImplementation; -use std::alloc::{alloc, dealloc, Layout}; -use std::ptr; +use crate::vm::method::DvmMethod; +use crate::vm::object_type::DvmImplementation; +use crate::vm::value::DvmValue; use std::rc::Rc; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq)] pub struct DvmObject { - data: Vec<*mut u8>, - implementation: Rc, -} - -fn layout_for(dm_type: &DmType) -> Layout { - match dm_type { - DmType::Byte => Layout::new::(), - DmType::Int => Layout::new::(), - DmType::Long => Layout::new::(), - DmType::USize => Layout::new::(), - DmType::Double => Layout::new::(), - DmType::Boolean => Layout::new::(), - DmType::Object => Layout::new::>(), - } + data: Vec, + implementation: Rc, } impl DvmObject { - pub fn new(implementation: Rc) -> Self { - let mut data = vec![ptr::null_mut(); implementation.fields().len()]; - for (index, field) in implementation.fields().iter().enumerate() { - data[index] = unsafe { alloc(layout_for(field.dm_type())) } - } + pub fn new(implementation: Rc) -> Self { DvmObject { - data, + data: vec![DvmValue::Empty; implementation.field_count()], implementation, } } - pub fn data(&self) -> &[*mut u8] { + fn get_field_index(&self, field_name: &str) -> usize { + self.implementation + .find_field(field_name, self) + .unwrap() + .index() + } + + pub fn data(&self) -> &[DvmValue] { &self.data } - pub fn implementation(&self) -> &DmImplementation { + pub fn implementation(&self) -> &DvmImplementation { &self.implementation } -} -impl Drop for DvmObject { - fn drop(&mut self) { - for (index, field) in self.implementation.fields().iter().enumerate() { - unsafe { dealloc(self.data[index], layout_for(field.dm_type())) } - } + pub fn read_field(&self, field_name: &str) -> &DvmValue { + &self.data[self.get_field_index(field_name)] + } + + pub fn take_field(&mut self, field_name: &str) -> DvmValue { + let field_index = self.get_field_index(field_name); + std::mem::take(&mut self.data[field_index]) + } + + pub fn write_field(&mut self, field_name: &str, value: DvmValue) { + let field_index = self.get_field_index(field_name); + self.data[field_index] = value; + } + + pub fn get_method(&self, method_name: &str) -> Option> { + self.implementation.find_method(method_name, self) } } diff --git a/src/vm/object_type.rs b/src/vm/object_type.rs index b8c0813..bf4310c 100644 --- a/src/vm/object_type.rs +++ b/src/vm/object_type.rs @@ -1,189 +1,35 @@ -use crate::vm::dm_type::DmType; +use crate::vm::field::DvmField; +use crate::vm::function::DvmFunction; +use crate::vm::interface::DmInterface; +use crate::vm::method::DvmMethod; use crate::vm::object::DvmObject; +use std::collections::HashMap; use std::fmt::Debug; use std::rc::Rc; #[derive(Debug, Eq)] -pub struct DmFn { +pub struct DvmImplementation { fqn: String, - short_name: String, - byte_code: Vec, - number_used_registers: usize, - return_register: Option, -} - -impl DmFn { - pub fn new( - fqn: &str, - short_name: &str, - byte_code: Vec, - number_used_registers: usize, - return_register: Option, - ) -> Self { - DmFn { - fqn: fqn.to_string(), - short_name: short_name.to_string(), - byte_code, - number_used_registers, - return_register, - } - } - - pub fn fqn(&self) -> &str { - self.fqn.as_str() - } - - pub fn short_name(&self) -> &str { - self.short_name.as_str() - } - - pub fn byte_code(&self) -> &Vec { - &self.byte_code - } - - pub fn number_used_registers(&self) -> usize { - self.number_used_registers - } - - pub fn return_register(&self) -> Option { - self.return_register - } -} - -impl PartialEq for DmFn { - fn eq(&self, other: &Self) -> bool { - self.fqn == other.fqn - } -} - -#[derive(Debug, Eq)] -pub struct DmMethod { - dm_fn: Rc, - implements: Option>, -} - -impl PartialEq for DmMethod { - fn eq(&self, other: &Self) -> bool { - self.dm_fn == other.dm_fn - } -} - -impl DmMethod { - pub fn new(dm_fn: DmFn, implements: Option>) -> Self { - DmMethod { - dm_fn: Rc::new(dm_fn), - implements, - } - } - - pub fn dm_fn(&self) -> Rc { - self.dm_fn.clone() - } -} - -#[derive(Debug, Eq)] -pub struct DmInterface { - fqn: String, - short_name: String, - functions: Vec>, - virtual_methods: Vec, -} - -impl PartialEq for DmInterface { - fn eq(&self, other: &Self) -> bool { - self.fqn == other.fqn - } -} - -impl DmInterface { - pub fn new(fqn: &str, short_name: &str) -> Self { - DmInterface { - fqn: fqn.to_string(), - short_name: short_name.to_string(), - functions: Vec::new(), - virtual_methods: Vec::new(), - } - } - - pub fn fqn(&self) -> &str { - self.fqn.as_str() - } - - pub fn short_name(&self) -> &str { - self.short_name.as_str() - } - - pub fn add_function(&mut self, dm_fn: DmFn) { - self.functions.push(Rc::new(dm_fn)); - } - - pub fn functions(&self) -> &Vec> { - &self.functions - } - - pub fn add_method(&mut self, dm_virtual_method: DmVirtualMethod) { - self.virtual_methods.push(dm_virtual_method); - } - - pub fn virtual_methods(&self) -> &Vec { - &self.virtual_methods - } -} - -#[derive(Debug, Eq)] -pub struct DmVirtualMethod { - fqn: String, - short_name: String, -} - -impl PartialEq for DmVirtualMethod { - fn eq(&self, other: &Self) -> bool { - self.fqn == other.fqn - } -} - -impl DmVirtualMethod { - pub fn new(fqn: &str, short_name: &str) -> Self { - DmVirtualMethod { - fqn: fqn.to_string(), - short_name: short_name.to_string(), - } - } - - pub fn fqn(&self) -> &str { - self.fqn.as_str() - } - - pub fn short_name(&self) -> &str { - self.short_name.as_str() - } -} - -#[derive(Debug, Eq)] -pub struct DmImplementation { - fqn: String, - short_name: String, interface: Option>, - functions: Vec>, - methods: Vec>, - fields: Vec, + static_functions: HashMap>, + methods: HashMap>, + fields: HashMap>, } -impl PartialEq for DmImplementation { +impl PartialEq for DvmImplementation { fn eq(&self, other: &Self) -> bool { self.fqn == other.fqn } } -impl DmImplementation { - pub fn new(fqn: &str, short_name: &str, interface: Option>) -> Self { - DmImplementation { +impl DvmImplementation { + pub fn new(fqn: &str, interface: Option>) -> Self { + DvmImplementation { fqn: fqn.to_string(), - short_name: short_name.to_string(), interface, - functions: Vec::new(), - methods: Vec::new(), - fields: Vec::new(), + static_functions: HashMap::new(), + methods: HashMap::new(), + fields: HashMap::new(), } } @@ -191,81 +37,30 @@ impl DmImplementation { self.fqn.as_str() } - pub fn short_name(&self) -> &str { - self.short_name.as_str() + pub fn add_function(&mut self, function: DvmFunction) { + self.static_functions + .insert(function.fqn().to_string(), Rc::new(function)); } - pub fn interface(&self) -> Option> { - self.interface.clone() + pub fn add_method(&mut self, dvm_method: DvmMethod) { + self.methods + .insert(dvm_method.fqn().to_string(), Rc::new(dvm_method)); } - pub fn functions(&self) -> &Vec> { - &self.functions + pub fn find_method(&self, name: &str, self_object: &DvmObject) -> Option> { + self.methods.get(name).cloned() } - pub fn add_function(&mut self, dm_fn: DmFn) { - self.functions.push(Rc::new(dm_fn)); + pub fn add_field(&mut self, dm_field: DvmField) { + self.fields + .insert(dm_field.name().to_string(), Rc::new(dm_field)); } - pub fn methods(&self) -> &Vec> { - &self.methods + pub fn find_field(&self, name: &str, self_object: &DvmObject) -> Option> { + self.fields.get(name).cloned() } - - pub fn add_method(&mut self, dm_method: DmMethod) { - self.methods.push(Rc::new(dm_method)); - } - - pub fn find_method(&self, name: &str, self_object: &DvmObject) -> Option<&DmMethod> { - for method in &self.methods { - if method.dm_fn.fqn == name { - return Some(method); - } else if let Some(implements) = &method.implements { - if implements.fqn == name { - return Some(method); - } - } - } - None - } - - pub fn fields(&self) -> &Vec { - &self.fields - } - - pub fn add_field(&mut self, dm_field: DmField) { - self.fields.push(dm_field); - } - - pub fn find_field(&self, name: &str, self_object: &DvmObject) -> Option<&DmField> { - self.fields.iter().find(|field| field.name == name) - } -} - -#[derive(Debug, Eq)] -pub struct DmField { - name: String, - dm_type: DmType, -} - -impl PartialEq for DmField { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - } -} - -impl DmField { - pub fn new(name: &str, dm_type: DmType) -> Self { - DmField { - name: name.to_string(), - dm_type, - } - } - - pub fn name(&self) -> &str { - &self.name - } - - pub fn dm_type(&self) -> &DmType { - &self.dm_type + + pub fn field_count(&self) -> usize { + self.fields.len() } } diff --git a/src/vm/platform/std_lib/core.rs b/src/vm/platform/std_lib/core.rs index 2617a80..04e9aa9 100644 --- a/src/vm/platform/std_lib/core.rs +++ b/src/vm/platform/std_lib/core.rs @@ -1,26 +1,22 @@ -use crate::vm::dvm_value::DvmValue; -use crate::vm::mem::read_field_by_name; use crate::vm::object::DvmObject; -use crate::vm::{DvmContext, DvmState}; +use crate::vm::value::DvmValue; +use crate::vm::DvmContext; +use std::cell::RefCell; use std::rc::Rc; -pub fn dm_print(args: Vec, _state: &mut DvmState, _context: &DvmContext) -> DvmValue { - if args.len() != 1 { - return DvmValue::Void; // TODO: make exception - } - print!("{}", get_string(&args[0])); - DvmValue::Void +/// ```deimos +/// // 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_println(args: Vec, _state: &mut DvmState, _context: &DvmContext) -> DvmValue { - if args.len() != 1 { - return DvmValue::Uninit; - } - println!("{}", get_string(&args[0])); - DvmValue::Void +pub fn dm_println(context: &mut DvmContext) { + println!("{}", get_string(context.pop_stack())); } -fn get_string(dvm_value: &DvmValue) -> String { +fn get_string(dvm_value: DvmValue) -> String { match dvm_value { DvmValue::Byte(b) => b.to_string(), DvmValue::Int(i) => i.to_string(), @@ -29,32 +25,30 @@ fn get_string(dvm_value: &DvmValue) -> String { DvmValue::Boolean(b) => b.to_string(), DvmValue::Object(object) => object_to_string(object.clone()), DvmValue::USize(u) => u.to_string(), - DvmValue::Uninit => String::from("Uninit"), - DvmValue::Void => String::from("Void"), + DvmValue::Array(a) => a.borrow().to_string(), + DvmValue::ConstantPointer(p) => p.to_string(), + DvmValue::Empty => String::from("Empty"), } } -fn object_to_string(alloc_object_rc: Rc) -> String { - if alloc_object_rc.implementation().fqn() == "std::core::StringImpl" { - extract_string_from_string(alloc_object_rc.clone()) +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 bytes_object = read_field_by_name("bytes", &string_object).expect_object(); - if bytes_object.implementation().fqn() != "std::core::ArrayImpl" { - panic!("String.bytes field is not a std::core::ArrayImpl"); +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."); } - - let address = read_field_by_name("ptr_address", &bytes_object).expect_usize(); - let size = read_field_by_name("ptr_size", &bytes_object).expect_usize(); - - let raw_bytes_pointer = address as *mut u8; - let mut v: Vec = Vec::new(); - for i in 0..size { - v.push(unsafe { raw_bytes_pointer.add(i).read() }); - } - String::from_utf8(v).unwrap() } diff --git a/src/vm/pointer.rs b/src/vm/pointer.rs new file mode 100644 index 0000000..70c905d --- /dev/null +++ b/src/vm/pointer.rs @@ -0,0 +1,13 @@ +use std::fmt::Display; + +#[derive(Debug, Clone, PartialEq)] +pub struct DvmPointer { + pub raw_pointer: *const u8, + pub length: usize, +} + +impl Display for DvmPointer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "DvmPointer({:p}, {})", self.raw_pointer, self.length) + } +} \ No newline at end of file diff --git a/src/vm/type.rs b/src/vm/type.rs new file mode 100644 index 0000000..db17db3 --- /dev/null +++ b/src/vm/type.rs @@ -0,0 +1,15 @@ +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum DvmType { + // Primitives + Byte, + Int, + Long, + Double, + Boolean, + USize, + + // Other + Object, + Array, + ConstantPointer +} diff --git a/src/vm/value.rs b/src/vm/value.rs new file mode 100644 index 0000000..e3f6723 --- /dev/null +++ b/src/vm/value.rs @@ -0,0 +1,196 @@ +use crate::vm::array::DvmArray; +use crate::vm::object::DvmObject; +use crate::vm::pointer::DvmPointer; +use std::cell::RefCell; +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +#[derive(Debug, PartialEq, Clone)] +pub enum DvmValue { + // Primitives + Byte(u8), + Int(i32), + Long(i64), + Double(f64), + USize(usize), + Boolean(bool), + + // Object + Object(Rc>), + + // Array + Array(Rc>), + + // Pointer to constant u8 + ConstantPointer(DvmPointer), + + // Null + Empty, +} + +impl Default for DvmValue { + fn default() -> Self { + DvmValue::Empty + } +} + +impl Display for DvmValue { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + DvmValue::Byte(b) => write!(f, "Byte({:x})", b), + DvmValue::Int(i) => write!(f, "Int({})", i), + DvmValue::Long(i) => write!(f, "Long({})", i), + DvmValue::Double(i) => write!(f, "Double({})", i), + DvmValue::USize(u) => write!(f, "USize({})", u), + 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::Empty => write!(f, "Empty"), + } + } +} + +impl DvmValue { + pub fn from_object(object: DvmObject) -> Self { + DvmValue::Object(Rc::new(RefCell::new(object))) + } + + pub fn expect_byte(&self) -> u8 { + if let DvmValue::Byte(b) = self { + *b + } else { + panic!("Expected DvmValue::Byte, but found DvmValue::{:?}", self); + } + } + + pub fn expect_int(&self) -> i32 { + if let DvmValue::Int(i) = self { + *i + } else { + panic!("Expected DvmValue::Int, but found DvmValue::{:?}", self); + } + } + + pub fn expect_long(&self) -> i64 { + if let DvmValue::Long(l) = self { + *l + } else { + panic!("Expected DvmValue::Long, but found DvmValue::{:?}", self); + } + } + + pub fn is_long(&self) -> bool { + match self { + DvmValue::Long(_) => true, + _ => false, + } + } + + pub fn expect_double(&self) -> f64 { + if let DvmValue::Double(d) = self { + *d + } else { + panic!("Expected DvmValue::Double, but found DvmValue::{:?}", self); + } + } + + pub fn expect_object(&self) -> Rc> { + if let DvmValue::Object(o) = self { + o.clone() + } else { + panic!("Expected DvmValue::Object, but found DvmValue::{:?}", self); + } + } + + pub fn map_object( + &self, + mapper: impl FnOnce(Rc>) -> T, + on_non_object: impl FnOnce(&Self) -> T, + ) -> T { + if let DvmValue::Object(o) = self { + mapper(o.clone()) + } else { + on_non_object(self) + } + } + + pub fn is_object(&self) -> bool { + match self { + DvmValue::Object(_) => true, + _ => false, + } + } + + pub fn expect_array(&self) -> Rc> { + if let DvmValue::Array(a) = self { + a.clone() + } else { + panic!("Expected DvmValue::Array, but found DvmValue::{:?}", self); + } + } + + pub fn is_array(&self) -> bool { + match self { + DvmValue::Array(_) => true, + _ => false, + } + } + + pub fn map_array( + &self, + mapper: impl FnOnce(Rc>) -> T, + on_non_array: impl FnOnce(&Self) -> T, + ) -> T { + if let DvmValue::Array(a) = self { + mapper(a.clone()) + } else { + on_non_array(self) + } + } + + pub fn expect_usize(&self) -> usize { + if let DvmValue::USize(u) = self { + *u + } else { + panic!("Expected DvmValue::USize, but found DvmValue::{:?}", self); + } + } + + pub fn is_usize(&self) -> bool { + match self { + DvmValue::USize(_) => true, + _ => false, + } + } + + pub fn as_usize(&self) -> Option { + match self { + DvmValue::Byte(b) => Some(*b as usize), + DvmValue::Int(i) => Some(*i as usize), + DvmValue::Long(l) => Some(*l as usize), + DvmValue::Double(d) => Some(*d as usize), + DvmValue::USize(u) => Some(*u), + _ => None, + } + } + + pub fn expect_boolean(&self) -> bool { + if let DvmValue::Boolean(b) = self { + *b + } else { + panic!("Expected DvmValue::Boolean, but found DvmValue::{:?}", self); + } + } + + pub fn expect_constant_pointer(&self) -> DvmPointer { + if let DvmValue::ConstantPointer(ptr) = self { + ptr.clone() + } else { + panic!( + "Expected DvmValue::ConstantPointer, but found DvmValue::{:?}", + self + ); + } + } +} diff --git a/src/vm/virtual_method.rs b/src/vm/virtual_method.rs new file mode 100644 index 0000000..e229b12 --- /dev/null +++ b/src/vm/virtual_method.rs @@ -0,0 +1,28 @@ +#[derive(Debug, Eq)] +pub struct DmVirtualMethod { + fqn: String, + short_name: String, +} + +impl PartialEq for DmVirtualMethod { + fn eq(&self, other: &Self) -> bool { + self.fqn == other.fqn + } +} + +impl DmVirtualMethod { + pub fn new(fqn: &str, short_name: &str) -> Self { + DmVirtualMethod { + fqn: fqn.to_string(), + short_name: short_name.to_string(), + } + } + + pub fn fqn(&self) -> &str { + self.fqn.as_str() + } + + pub fn short_name(&self) -> &str { + self.short_name.as_str() + } +}