diff --git a/src/bin/dvm/main.rs b/src/bin/dvm/main.rs index c2ea22b..9332034 100644 --- a/src/bin/dvm/main.rs +++ b/src/bin/dvm/main.rs @@ -5,7 +5,7 @@ fn main() { let mut code: Vec = Vec::new(); add_mov_int(&mut code, 0, 42); add_platform_call_to(&mut code, &String::from("std::core::print"), 0, 1, &vec![0u8]); - let mut vm = DmVirtualMachine::new(); + let mut vm = DmVirtualMachine::new(Vec::new()); vm.run(&mut code); println!() } \ No newline at end of file diff --git a/src/vm/mem.rs b/src/vm/mem.rs new file mode 100644 index 0000000..247c14d --- /dev/null +++ b/src/vm/mem.rs @@ -0,0 +1,78 @@ +use crate::vm::types::{DmImplementation, DmProperty, DmType}; +use crate::vm::values::DmValue; +use std::alloc::Layout; + +pub struct DmAllocObject<'a> { + pub data: *mut u8, + pub size: usize, + pub layout: Layout, + pub object_type: &'a DmImplementation<'a>, +} + +pub unsafe fn get_property_value(dm_property: &DmProperty, dm_property_object: &DmAllocObject) -> DmValue { + let mut data: Vec = Vec::with_capacity(dm_property.dm_type.size_in_bytes()); + for i in dm_property.data_offset..(dm_property.data_offset + dm_property.dm_type.size_in_bytes()) { + data.push(dm_property_object.data.offset(i as isize).read()); + } + match dm_property.dm_type { + DmType::Byte => { + DmValue::DmByte(data[0]) + } + DmType::Int => { + DmValue::DmInt(i32::from_ne_bytes(data[0..4].try_into().unwrap())) + } + DmType::Long => { + DmValue::DmLong(i64::from_ne_bytes(data[0..8].try_into().unwrap())) + } + DmType::Double => { + DmValue::DmDouble(f64::from_ne_bytes(data[0..8].try_into().unwrap())) + } + DmType::Boolean => { + DmValue::DmBoolean(i32::from_ne_bytes(data[0..4].try_into().unwrap()) != 0) + } + DmType::ObjectPointer(_) => { + DmValue::DmPointer(usize::from_ne_bytes(data[0..8].try_into().unwrap()) as *mut DmAllocObject) + } + DmType::ByteArray(_) => { + DmValue::DmByteArray(data) + } + DmType::IntArray(length) => { + let mut result = Vec::with_capacity(length); + for i in 0..length { + result.push(i32::from_ne_bytes(data[(i * 4)..(i * 4 + 4)].try_into().unwrap())); + } + DmValue::DmIntArray(result) + } + DmType::LongArray(length) => { + let mut result = Vec::with_capacity(length); + for i in 0..length { + result.push(i64::from_ne_bytes(data[i * 8..(i * 8 + 8)].try_into().unwrap())); + } + DmValue::DmLongArray(result) + } + DmType::DoubleArray(length) => { + let mut result = Vec::with_capacity(length); + for i in 0..length { + result.push(f64::from_ne_bytes(data[i * 8..(i * 8 + 8)].try_into().unwrap())); + } + DmValue::DmDoubleArray(result) + } + DmType::BooleanArray(length) => { + let mut result = Vec::with_capacity(length); + for i in 0..length { + result.push(i32::from_ne_bytes(data[(i * 4)..(i * 4 + 4)].try_into().unwrap()) != 0); + } + DmValue::DmBooleanArray(result) + } + DmType::ObjectPointerArray(length, _) => { + let mut result = Vec::with_capacity(length); + for i in 0..length { + result.push(usize::from_ne_bytes(data[(i * 8)..(i * 8 + 8)].try_into().unwrap()) as *mut DmAllocObject); + } + DmValue::DmPointerArray(result) + } + DmType::Unit => { + DmValue::DmUnit + } + } +} \ No newline at end of file diff --git a/src/vm/mod.rs b/src/vm/mod.rs index c36465a..b0639c2 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -4,13 +4,15 @@ pub mod platform; pub mod types; pub mod util; pub mod values; +mod mem; -use crate::vm::module::DmFunction; +use crate::vm::mem::DmAllocObject; +use crate::vm::module::DmModule; use crate::vm::platform::init_platform_functions; +use crate::vm::types::{DmFn, DmImplementation}; use op_codes::*; use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::collections::HashMap; -use std::ops::Index; use types::DmType; use util::{get_32_le, get_64_le}; use values::DmValue; @@ -25,15 +27,15 @@ enum CallFrame { pub struct PlatformCallFrame { pub name: String, - pub args: Vec, - pub arg_types: Vec, + pub args: Vec, } struct DeimosCallFrame { return_address: usize, } -pub struct DmVirtualMachine { +pub struct DmVirtualMachine<'a> { + modules: Vec>, platform_functions: HashMap, ip: usize, call_stack: Vec, @@ -41,9 +43,10 @@ pub struct DmVirtualMachine { register_state_stack: Vec>, } -impl DmVirtualMachine { - pub fn new() -> DmVirtualMachine { +impl DmVirtualMachine<'_> { + pub fn new(modules: Vec) -> DmVirtualMachine { DmVirtualMachine { + modules, ip: 0, registers: Vec::new(), platform_functions: init_platform_functions(), @@ -54,7 +57,7 @@ impl DmVirtualMachine { pub fn call( &mut self, - dm_function: &DmFunction, + dm_function: &DmFn, args: Vec, ) -> DmValue { // save current state @@ -110,15 +113,36 @@ impl DmVirtualMachine { i += 3; } ALLOC => { - let target_register = code[i + 1] as usize; - let size = get_32_le!(code, i, 2, usize); + i += 1; + let target_register = code[i] as usize; + i += 1; + let symbol_name_length = get_32_le!(code, i, 0, usize); + i += 4; + let raw_symbol_name = code[i..(i + symbol_name_length)].to_vec(); + i += symbol_name_length; + let symbol_name = String::from_utf8(raw_symbol_name).unwrap(); + + // find implementation + let mut implementation_result: Option<&DmImplementation> = None; + 'module_find: for module in self.modules.iter() { + if let Some(dm_implementation) = module.implementations.get(&symbol_name) { + implementation_result = Some(dm_implementation); + break 'module_find; + } + } + if implementation_result == None { + panic!("Implementation {} not found", symbol_name); + } + + let dm_implementation = implementation_result.unwrap(); + let size = dm_implementation.size_in_bytes; let layout = Layout::from_size_align(size, 4).unwrap(); let pointer = unsafe { alloc_zeroed(layout) }; - let dm_object = Box::new(DmObject { + let dm_object = Box::new(DmAllocObject { + object_type: dm_implementation, data: pointer, size, layout, - object_type: todo!(), }); let dm_object_pointer = Box::into_raw(dm_object); self.registers.insert(target_register, DmPointer(dm_object_pointer)); @@ -201,30 +225,6 @@ impl DmVirtualMachine { } -pub struct DmObjectType { - name: String, - properties: HashMap, - fields: HashMap, - methods: HashMap, -} - -pub struct DmObject { - object_type: Box, - data: *mut u8, - size: usize, - layout: Layout, -} - -pub struct DmObjectProperty { - name: String, - property_type: DmType, -} - -pub struct DmObjectField { - name: String, - field_type: DmType, -} - #[cfg(test)] mod dvm_run_tests { use super::*; @@ -240,7 +240,7 @@ mod dvm_run_tests { fn mov_1_as_int() { let mut code = Vec::new(); add_mov_int(&mut code, 0, 1); - let mut vm = DmVirtualMachine::new(); + let mut vm = DmVirtualMachine::new(Vec::new()); vm.run(&code); assert_register!(DmInt(1), vm.registers.get(0)); } @@ -249,7 +249,7 @@ mod dvm_run_tests { fn move_65535_as_int() { let mut code = Vec::new(); add_mov_int(&mut code, 0, 0xffff); - let mut vm = DmVirtualMachine::new(); + let mut vm = DmVirtualMachine::new(Vec::new()); vm.run(&code); assert_register!(DmInt(0xffff), vm.registers.get(0)); } @@ -258,7 +258,7 @@ mod dvm_run_tests { fn move_int_max_as_int() { let mut code = Vec::new(); add_mov_int(&mut code, 0, 0x0fff_ffff); - let mut vm = DmVirtualMachine::new(); + let mut vm = DmVirtualMachine::new(Vec::new()); vm.run(&code); assert_register!(DmInt(0x0fff_ffff), vm.registers.get(0)); } @@ -268,7 +268,7 @@ mod dvm_run_tests { let mut code = Vec::new(); add_mov_int(&mut code, 1, 1); add_mov_register(&mut code, 0, 1); - let mut vm = DmVirtualMachine::new(); + let mut vm = DmVirtualMachine::new(Vec::new()); vm.registers.resize(2, DmUnit); vm.run(&code); assert_register!(DmInt(1), vm.registers.get(0)); @@ -280,7 +280,7 @@ mod dvm_run_tests { let mut code = Vec::new(); add_alloc(&mut code, 0, 4); add_mov_int_to(&mut code, 0, 0, 0xff); - let mut vm = DmVirtualMachine::new(); + let mut vm = DmVirtualMachine::new(Vec::new()); vm.run(&code); let box_address = vm.registers.get(0).unwrap().clone(); match box_address { @@ -299,7 +299,7 @@ mod dvm_run_tests { let mut code = Vec::new(); add_alloc(&mut code, 0, 4); add_dealloc(&mut code, 0); - let mut vm = DmVirtualMachine::new(); + let mut vm = DmVirtualMachine::new(Vec::new()); vm.run(&code); assert_register!(DmUnit, vm.registers.get(0)); } diff --git a/src/vm/module.rs b/src/vm/module.rs index cd5fbfa..420fa80 100644 --- a/src/vm/module.rs +++ b/src/vm/module.rs @@ -1,17 +1,20 @@ use crate::get_32_le; +use crate::vm::types::{DmFn, DmImplementation, DmInterface}; use std::collections::HashMap; -use std::io::Read; pub const DEIMOS_MAGIC_NUMBER: u64 = 0x00_00_64_65_69_6d_6f_73; // ascii 'deimos' -const DEIMOS_MAGIC_STRING: [u8; 6] = [0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73]; // ascii 'deimos' +pub const DEIMOS_MAGIC_STRING: [u8; 6] = [0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73]; // ascii 'deimos' -pub const VERSION_STRING: &str = "0.1.0"; +pub const COMPILER_VERSION_STRING: &str = "0.1.0"; -pub struct DmModule { - name: String, - version: String, - constants: HashMap, - functions: HashMap, +pub struct DmModule<'a> { + pub compiler_version: String, + pub fqn: String, + pub short_name: String, + pub constants: HashMap, + pub interfaces: HashMap>, + pub implementations: HashMap>, + pub functions: HashMap, } pub enum DmConstant { @@ -21,12 +24,6 @@ pub enum DmConstant { String(String), } -pub struct DmFunction { - pub name: String, - pub byte_code: Vec, - pub num_registers: usize, -} - const CONST_SYMBOL: u8 = 0x01; const FUNCTION_SYMBOL: u8 = 0x02; @@ -74,10 +71,10 @@ pub fn write_module(module: DmModule) -> Vec { push_byte_array!(result, DEIMOS_MAGIC_STRING); // Push version string - push_string!(result, module.version); + push_string!(result, module.compiler_version); // Push module name length, little endian - push_string!(result, module.name); + push_string!(result, module.fqn); result } diff --git a/src/vm/platform/std_lib/core.rs b/src/vm/platform/std_lib/core.rs index 1debec1..5a7941c 100644 --- a/src/vm/platform/std_lib/core.rs +++ b/src/vm/platform/std_lib/core.rs @@ -1,26 +1,5 @@ -use crate::vm::module::DmFunction; use crate::vm::DmValue::*; -use crate::vm::{DmObject, DmValue, DmVirtualMachine}; - -fn get_method<'a>(ptr: *mut DmObject, name: String) -> Option<&'a DmFunction> { - unsafe { - (*ptr).object_type.methods.get(&name) - } -} - -fn get_rust_string_from_dm_object(ptr: &*mut DmObject) -> String { - unsafe { - let dm_object = Box::from_raw(*ptr); - format!("{}@{:?}", dm_object.object_type.name, dm_object.data) - } -} - -fn get_rust_string_from_dm_string(ptr: *mut DmObject) -> String { - unsafe { - let dm_string = Box::from_raw(ptr); - todo!() - } -} +use crate::vm::{mem, DmValue, DmVirtualMachine}; pub fn dm_print(args: Vec, vm: &mut DmVirtualMachine) -> DmValue { if args.len() != 1 { @@ -42,20 +21,26 @@ pub fn dm_print(args: Vec, vm: &mut DmVirtualMachine) -> DmValue { DmBoolean(b) => { print!("{}", *b); } - DmPointer(ptr) => { - if let Some(to_string) = get_method(*ptr, String::from("to_string")) { - let call_result = vm.call(&to_string, vec![args[0].clone()]); - match call_result { - DmPointer(dm_string_ptr) => { - let string = get_rust_string_from_dm_string(dm_string_ptr); - print!("{}", string); - } - _ => { - // TODO: vm throw or return exception? + DmPointer(ptr) => unsafe { + let dm_alloc_object = Box::from_raw(*ptr); + let dm_object_type = &dm_alloc_object.object_type; + if let Some(to_string_method) = dm_object_type.get_method(String::from("std::core::Object::to_string"), &dm_alloc_object) { + let call_result = vm.call(to_string_method, vec![args[0].clone()]); + if let DmPointer(dm_string_pointer) = call_result { + let dm_string_object = Box::from_raw(dm_string_pointer); + let bytes_property = dm_string_object.object_type.get_property(String::from("bytes"), &dm_string_object).unwrap(); + let string_bytes_value = mem::get_property_value(bytes_property, &dm_string_object); + if let DmByteArray(raw_string_bytes) = string_bytes_value { + // TODO: other encodings + print!("{}", String::from_utf8(raw_string_bytes).unwrap()); + } else { + panic!("Expected std::core::String.bytes to be a ByteArray.") } + } else { + panic!("Expected {} to return a string.", to_string_method.fqn) } } else { - print!("{}", get_rust_string_from_dm_object(ptr)); + println!("{}@{:?}", dm_object_type.get_fqn(), dm_alloc_object.data) } }, DmByteArray(bs) => { diff --git a/src/vm/types.rs b/src/vm/types.rs index 36ebf99..a1e93e1 100644 --- a/src/vm/types.rs +++ b/src/vm/types.rs @@ -1,14 +1,162 @@ -#[derive(PartialEq, Eq, Clone, Debug, Copy)] -pub enum DmType { +use crate::vm::mem::DmAllocObject; +use std::collections::HashMap; + +#[derive(Debug, PartialEq, Eq)] +pub enum DmType<'a> { + Byte, Int, Long, Double, Boolean, - Pointer, - IntArray, - LongArray, - DoubleArray, - BooleanArray, - PointerArray, + ObjectPointer(&'a dyn DmObjectType), + ByteArray(usize), + IntArray(usize), + LongArray(usize), + DoubleArray(usize), + BooleanArray(usize), + ObjectPointerArray(usize, &'a dyn DmObjectType), Unit, } + +impl DmType<'_> { + pub fn size_in_bytes(&self) -> usize { + match self { + DmType::Byte => 1, + DmType::Int => 4, + DmType::Long => 8, + DmType::Double => 8, + DmType::Boolean => 4, + DmType::ObjectPointer(_) => 8, + DmType::ByteArray(length) => *length, + DmType::IntArray(length) => *length * 4, + DmType::LongArray(length) => *length * 8, + DmType::DoubleArray(length) => *length * 8, + DmType::BooleanArray(length) => *length * 4, + DmType::ObjectPointerArray(length, _) => length * 8, + DmType::Unit => 0 + } + } +} + +pub trait DmObjectType { + fn get_fqn(&self) -> &String; + fn get_method(&self, name: String, self_object: &DmAllocObject) -> Option<&DmFn>; + fn get_property(&self, name: String, self_object: &DmAllocObject) -> Option<&DmProperty>; +} + +#[derive(Debug, Eq)] +pub struct DmFn { + pub fqn: String, + pub short_name: String, + pub byte_code: Vec, + pub num_registers: usize, +} + +impl PartialEq for DmFn { + fn eq(&self, other: &Self) -> bool { + self.fqn == other.fqn + } +} + +#[derive(Debug, Eq)] +pub struct DmInterface<'a> { + fqn: String, + short_name: String, + properties: HashMap>, + virtual_methods: HashMap, + impl_methods: HashMap, +} + +impl PartialEq for DmInterface<'_> { + fn eq(&self, other: &Self) -> bool { + self.fqn == other.fqn + } +} + +impl DmObjectType for DmInterface<'_> { + fn get_fqn(&self) -> &String { + &self.fqn + } + + fn get_method(&self, name: String, self_object: &DmAllocObject) -> Option<&DmFn> { + if self.impl_methods.contains_key(&name) { + self.impl_methods.get(&name) + } else if self.virtual_methods.contains_key(&name) { + self_object.object_type.get_method(name, &self_object) + } else { + None + } + } + + fn get_property(&self, name: String, self_object: &DmAllocObject) -> Option<&DmProperty> { + self.properties.get(&name) + } +} + +#[derive(Debug, Eq)] +pub struct DmVirtualMethod { + pub fqn: String, + pub short_name: String, +} + +impl PartialEq for DmVirtualMethod { + fn eq(&self, other: &Self) -> bool { + self.fqn == other.fqn + } +} + +#[derive(Debug, Eq)] +pub struct DmImplementation<'a> { + pub fqn: String, + pub short_name: String, + pub interface: &'a DmInterface<'a>, + pub properties: HashMap>, + pub fields: HashMap>, + pub size_in_bytes: usize, + pub methods: HashMap +} + +impl PartialEq for DmImplementation<'_> { + fn eq(&self, other: &Self) -> bool { + self.fqn == other.fqn + } +} + +impl DmObjectType for DmImplementation<'_> { + fn get_fqn(&self) -> &String { + &self.fqn + } + + fn get_method(&self, name: String, self_object: &DmAllocObject) -> Option<&DmFn> { + self.methods.get(&name) + } + + fn get_property(&self, name: String, self_object: &DmAllocObject) -> Option<&DmProperty> { + self.properties.get(&name) + } +} + +#[derive(Debug, Eq)] +pub struct DmProperty<'a> { + pub name: String, + pub data_offset: usize, + pub dm_type: DmType<'a> +} + +impl PartialEq for DmProperty<'_> { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +#[derive(Debug, Eq)] +pub struct DmField<'a> { + name: String, + dm_type: DmType<'a>, +} + +impl PartialEq for DmField<'_> { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} \ No newline at end of file diff --git a/src/vm/values.rs b/src/vm/values.rs index 2d92c31..80cc082 100644 --- a/src/vm/values.rs +++ b/src/vm/values.rs @@ -1,4 +1,4 @@ -use crate::vm::DmObject; +use crate::vm::mem::DmAllocObject; #[derive(Debug, Clone, PartialEq)] pub enum DmValue { @@ -7,12 +7,12 @@ pub enum DmValue { DmLong(i64), DmDouble(f64), DmBoolean(bool), - DmPointer(*mut DmObject), + DmPointer(*mut DmAllocObject), DmByteArray(Vec), DmIntArray(Vec), DmLongArray(Vec), DmDoubleArray(Vec), DmBooleanArray(Vec), - DmPointerArray(Vec<*mut DmObject>), + DmPointerArray(Vec<*mut DmAllocObject>), DmUnit, -} \ No newline at end of file +}