diff --git a/Cargo.toml b/Cargo.toml index 09c55c4..b0dfb8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,8 @@ edition = "2021" name = "dmc" path = "src/bin/compiler/main.rs" +[[bin]] +name = "dm" +path = "src/bin/dvm/main.rs" + [dependencies] diff --git a/src/bin/dvm/main.rs b/src/bin/dvm/main.rs new file mode 100644 index 0000000..2e87359 --- /dev/null +++ b/src/bin/dvm/main.rs @@ -0,0 +1,14 @@ +use std::process::exit; +use deimos::vm::DmVirtualMachine; +use deimos::vm::op_codes::{add_mov_int, add_platform_call_to}; + +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"), 1, &vec![0u8]); + let mut vm = DmVirtualMachine::new(); + if let Err(_) = vm.run(&mut code) { + eprintln!("There was an exception."); + exit(1); + } +} \ No newline at end of file diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 7398436..013f79f 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,35 +1,309 @@ -mod module; -mod op_codes; -mod platform; -mod types; +pub mod module; +pub mod op_codes; +pub mod platform; +pub mod types; mod util; use crate::vm::module::DmFunction; +use crate::vm::platform::init_platform_functions; use op_codes::*; -use platform::PlatformCallFrame; 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}; -pub type PlatformFunction = fn(&mut PlatformCallFrame) -> Result, String>; +pub type PlatformFunction = fn(PlatformCallFrame) -> Result, String>; -pub struct DmVirtualMachine { - registers: Vec, - register_types: Vec, - platform_functions: HashMap, +enum CallFrame<'a> { + PlatformCall(PlatformCallFrame<'a>), + DeimosCall(DeimosCallFrame<'a>) } -impl DmVirtualMachine { - pub fn call( - &self, - dm_function: &DmFunction, - args: Vec, - arg_types: Vec, - ) -> Result<(u64, DmType), String> { - run(&dm_function.byte_code, todo!(), todo!()); - todo!() +pub struct PlatformCallFrame<'a> { + pub name: String, + pub args: Vec, + pub arg_types: Vec, + pub vm: &'a mut DmVirtualMachine<'a> +} + +struct DeimosCallFrame<'a> { + return_address: usize, + dm_function: &'a DmFunction +} + +struct RegisterSet { + size: usize, + registers: Vec, + register_types: Vec, +} + +type RegisterValue = (u64, DmType); + +impl RegisterSet { + fn new(size: usize) -> RegisterSet { + RegisterSet { + size, + registers: vec![0; size], + register_types: vec![DmType::Unit; size], + } } + + fn get(&self, register_number: usize) -> RegisterValue { + (self.registers[register_number], self.register_types[register_number]) + } + + fn set_u32(&mut self, register_number: usize, value: u32, dm_type: DmType) { + self.registers[register_number] = value as u64; + self.register_types[register_number] = dm_type; + } + + fn set_u64(&mut self, register_number: usize, value: u64, dm_type: DmType) { + self.registers[register_number] = value; + self.register_types[register_number] = dm_type; + } + + fn clear(&mut self) { + self.registers = vec![0; self.size]; + self.register_types = vec![DmType::Unit; self.size]; + } + + fn ensure_capacity(&mut self, size: usize) { + self.registers.resize(size, 0); + self.register_types.resize(size, DmType::Unit); + } + + fn iter(&self) -> RegisterSetIterator { + RegisterSetIterator::new(&self.registers, &self.register_types) + } +} + +struct RegisterSetIterator<'a> { + i: usize, + registers: &'a Vec, + register_types: &'a Vec, +} + +impl RegisterSetIterator<'_> { + fn new<'a>(registers: &'a Vec, register_types: &'a Vec) -> RegisterSetIterator<'a> { + RegisterSetIterator { + i: 0usize, + registers, + register_types + } + } +} + +impl<'a> Iterator for RegisterSetIterator<'a> { + type Item = RegisterValue; + + fn next(&mut self) -> Option { + if self.i < self.registers.len() { + let some = Some((self.registers[self.i], self.register_types[self.i])); + self.i += 1; + some + } else { + None + } + } +} + +impl Clone for RegisterSet { + fn clone(&self) -> Self { + RegisterSet { + size: self.size, + registers: self.registers.clone(), + register_types: self.register_types.clone(), + } + } +} + +pub struct DmVirtualMachine<'a> { + platform_functions: HashMap, + ip: usize, + call_stack: Vec>, + register_set: RegisterSet, + register_state_stack: Vec, +} + +impl DmVirtualMachine<'_> { + pub fn new<'a>() -> DmVirtualMachine<'a> { + DmVirtualMachine { + ip: 0, + register_set: RegisterSet::new(0), + platform_functions: init_platform_functions(), + call_stack: Vec::new(), + register_state_stack: Vec::new(), + } + } + + pub fn call( + &mut self, + dm_function: &DmFunction, + args: [u64; ArgLen], + arg_types: [DmType; ArgLen], + ) -> Result<(u64, DmType), String> { + // save current state + self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame { + return_address: self.ip, + dm_function + })); + self.register_state_stack.push(self.register_set.clone()); + + // zero registers and make sure there are enough for dm_function + self.register_set.clear(); + self.register_set.ensure_capacity(dm_function.num_registers); + + // push args + for i in 0..args.len() { + let arg = args[i]; + let arg_type = arg_types[i]; + self.register_set.set_u64(i, arg, arg_type); + } + + // run the byte code + let call_result = self.run(&dm_function.byte_code); + + // restore state + self.register_set = self.register_state_stack.pop().unwrap(); + if let CallFrame::DeimosCall(deimos_call_frame) = self.call_stack.pop().unwrap() { + self.ip = deimos_call_frame.return_address; + } + + // return result + if let Err(_) = call_result { + Err(String::from(format!("Failed to execute function {}", &dm_function.name))) + } else { + Ok(self.register_set.get(0)) + } + } + + pub fn run(&mut self, code: &Vec) -> Result<(), ()> { + let mut i = 0; + while i < code.len() { + match code[i] { + MOV_INT => { + let target_register = code[i + 1] as usize; + let operand = get_32_le!(code, i, 2, u32); + self.register_set.set_u32(target_register, operand, DmType::Int); + i += 6; + } + MOV_LONG => { + let target_register = code[i + 1] as usize; + let operand = get_64_le!(code, i, 2, u64); + self.register_set.set_u64(target_register, operand, DmType::Long); + i += 10; + } + MOV_DOUBLE => { /* todo */ } + MOV_REGISTER => { + let target_register = code[i + 1] as usize; + let source_register = code[i + 2] as usize; + let (value, dm_type) = self.register_set.get(source_register); + self.register_set.set_u64(target_register, value, dm_type); + i += 3; + } + ALLOC => { + let target_register = code[i + 1] as usize; + let size = get_32_le!(code, i, 2, usize); + let layout = Layout::from_size_align(size, 4).unwrap(); + let pointer = unsafe { alloc_zeroed(layout) }; + let dm_object = Box::new(DmObject { + data: pointer, + size, + layout, + object_type: todo!(), + }); + let dm_object_pointer = Box::into_raw(dm_object) as u64; + self.register_set.set_u64(target_register, dm_object_pointer as u64, DmType::Pointer); + i += 6; + } + DEALLOC => { + let target_register = code[i + 1] as usize; + let (box_address, register_type) = self.register_set.get(target_register); + if register_type != DmType::Pointer { + panic!("Attempt to deallocate at the address stored in a register that is not a pointer."); + } + unsafe { + let dm_object = Box::from_raw(box_address as *mut DmObject); + dealloc(dm_object.data, dm_object.layout); + } + self.register_set.set_u64(target_register, 0, DmType::Unit); + i += 2; + } + MOV_INT_TO => { + let target_register = code[i + 1] as usize; + let (box_address, register_type) = self.register_set.get(target_register); + if register_type != DmType::Pointer { + panic!("target_register {} is not a Pointer", target_register); + } + let offset = get_32_le!(code, i, 2, isize); + let new_address = unsafe { + let dm_object = Box::from_raw(box_address as *mut DmObject); + let pointer = dm_object.data; + pointer.offset(offset).write(code[i + 6]); + pointer.offset(offset + 1).write(code[i + 7]); + pointer.offset(offset + 2).write(code[i + 8]); + pointer.offset(offset + 3).write(code[i + 9]); + Box::into_raw(dm_object) as u64 + }; + self.register_set.set_u64(target_register, new_address, DmType::Pointer); + i += 10; + } + PLATFORM_CALL => { + i += 1; + + let symbol_name_length = get_32_le!(code, i, 1, usize); + i += 4; + + let symbol_name_raw = code[i..(i + symbol_name_length)].to_vec(); + i += symbol_name_length; + + let symbol_name = String::from_utf8(symbol_name_raw).unwrap(); + + let arg_registers_length = code[i] as usize; + i += 1; + + let arg_registers = code[i..(i + arg_registers_length)].to_vec(); + i += arg_registers_length; + + let platform_function_result = self.platform_functions.get(&symbol_name); + if platform_function_result.is_none() { + panic!("Unknown function {}", symbol_name); + } + let platform_function = platform_function_result.unwrap(); + + let mut args = Vec::new(); + let mut arg_types = Vec::new(); + for (value, dm_type) in self.register_set.iter() { + args.push(value); + arg_types.push(dm_type); + } + + match platform_function(PlatformCallFrame { + name: symbol_name, + args, + arg_types, + vm: self + }) { + Ok(result_opt) => { + match result_opt { + Some((result, result_type)) => { + // todo: put in register + }, + None => { + // TODO: put Unit in register + } + } + }, + Err(e) => panic!("{}", e) + } + } + _ => panic!("Invalid code instruction"), + } + } + Ok(()) + } + } pub struct DmObjectType { @@ -56,83 +330,6 @@ pub struct DmObjectField { field_type: DmType, } -pub fn run(code: &Vec, registers: &mut Vec, register_types: &mut Vec) { - let mut i = 0; - while i < code.len() { - match code[i] { - MOV_INT => { - let target_register = code[i + 1] as usize; - let operand = get_32_le!(code, i, 2, u32); - registers[target_register] = operand as u64; - register_types[target_register] = DmType::Int; - i += 6; - } - MOV_LONG => { - let target_register = code[i + 1] as usize; - let operand = get_64_le!(code, i, 2, u64); - registers[target_register] = operand; - register_types[target_register] = DmType::Long; - i += 10; - } - MOV_DOUBLE => { /* todo */ } - MOV_REGISTER => { - let target_register = code[i + 1] as usize; - let source_register = code[i + 2] as usize; - registers[target_register] = registers[source_register]; - register_types[target_register] = register_types[source_register].clone(); - i += 3; - } - ALLOC => { - let target_register = code[i + 1] as usize; - let size = get_32_le!(code, i, 2, usize); - let layout = Layout::from_size_align(size, 4).unwrap(); - let pointer = unsafe { alloc_zeroed(layout) }; - let dm_object = Box::new(DmObject { - data: pointer, - size, - layout, - object_type: todo!(), - }); - let dm_object_pointer = Box::into_raw(dm_object) as u64; - registers[target_register] = dm_object_pointer; - register_types[target_register] = DmType::Pointer; - i += 6; - } - DEALLOC => { - let target_register = code[i + 1] as usize; - let box_address = registers[target_register]; - unsafe { - let dm_object = Box::from_raw(box_address as *mut DmObject); - dealloc(dm_object.data, dm_object.layout); - } - registers[target_register] = 0; - register_types[target_register] = DmType::Int; - i += 2; - } - MOV_INT_TO => { - let target_register = code[i + 1] as usize; - if register_types[target_register] != DmType::Pointer { - panic!("target_register {} is not a Pointer", target_register); - } - let offset = get_32_le!(code, i, 2, isize); - let box_address = registers[target_register]; - let new_address = unsafe { - let dm_object = Box::from_raw(box_address as *mut DmObject); - let pointer = dm_object.data; - pointer.offset(offset).write(code[i + 6]); - pointer.offset(offset + 1).write(code[i + 7]); - pointer.offset(offset + 2).write(code[i + 8]); - pointer.offset(offset + 3).write(code[i + 9]); - Box::into_raw(dm_object) as u64 - }; - registers[target_register] = new_address; - i += 10; - } - _ => panic!("Invalid code instruction"), - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/vm/module.rs b/src/vm/module.rs index 24d7804..cd5fbfa 100644 --- a/src/vm/module.rs +++ b/src/vm/module.rs @@ -24,6 +24,7 @@ pub enum DmConstant { pub struct DmFunction { pub name: String, pub byte_code: Vec, + pub num_registers: usize, } const CONST_SYMBOL: u8 = 0x01; diff --git a/src/vm/op_codes.rs b/src/vm/op_codes.rs index 01a2ecd..1ff5ecf 100644 --- a/src/vm/op_codes.rs +++ b/src/vm/op_codes.rs @@ -81,8 +81,12 @@ pub fn add_mov_int_to(code: &mut Vec, register: u8, offset: u32, operand: u3 push_number!(code, operand); } -pub fn add_platform_call_to(code: &mut Vec, symbol_name: &String) { +pub fn add_platform_call_to(code: &mut Vec, symbol_name: &String, arg_registers_length: u8, arg_registers: &Vec) { code.push(PLATFORM_CALL); push_number!(code, symbol_name.len()); push_string!(code, symbol_name); + push_number!(code, arg_registers_length); + for &b in arg_registers { + code.push(b); + } } diff --git a/src/vm/platform/mod.rs b/src/vm/platform/mod.rs index 4451f28..e451f06 100644 --- a/src/vm/platform/mod.rs +++ b/src/vm/platform/mod.rs @@ -1,15 +1,9 @@ use crate::vm::platform::std_lib::core::dm_print; -use crate::vm::{DmVirtualMachine, PlatformFunction}; +use crate::vm::PlatformFunction; use std::collections::HashMap; mod std_lib; -pub struct PlatformCallFrame { - args: Vec, - arg_types: Vec, - vm: DmVirtualMachine, -} - pub fn init_platform_functions() -> HashMap { let mut fns: HashMap = HashMap::new(); fns.insert(String::from("std::core::print"), dm_print); diff --git a/src/vm/platform/std_lib/core.rs b/src/vm/platform/std_lib/core.rs index 61bb57b..3b7e052 100644 --- a/src/vm/platform/std_lib/core.rs +++ b/src/vm/platform/std_lib/core.rs @@ -1,5 +1,5 @@ -use crate::vm::platform::PlatformCallFrame; use crate::vm::types::DmType; +use crate::vm::PlatformCallFrame; use crate::vm::DmObject; use DmType::*; @@ -7,7 +7,7 @@ pub struct DmString { data: String, } -pub fn dm_print(frame: &mut PlatformCallFrame) -> Result, String> { +pub fn dm_print(frame: PlatformCallFrame) -> Result, String> { if frame.args.len() != 1 { return Err(String::from("std::core::print requires one argument.")); } @@ -28,10 +28,9 @@ pub fn dm_print(frame: &mut PlatformCallFrame) -> Result, .methods .get(&String::from("to_string")) { - let call_result = - frame + let call_result = frame .vm - .call(to_string_method, vec![frame.args[0]], vec![Pointer]); + .call(&to_string_method, [frame.args[0]], [frame.arg_types[0]]); if call_result.is_err() { return Err(call_result.unwrap_err()); } @@ -43,6 +42,12 @@ pub fn dm_print(frame: &mut PlatformCallFrame) -> Result, print!("{}@{:?}", dm_object.object_type.name, dm_object.data); } }, + Unit => { + print!("Unit") + }, + Exception => { + print!("Exception") + } } Ok(None) } diff --git a/src/vm/types.rs b/src/vm/types.rs index 09cad83..ecd8fc7 100644 --- a/src/vm/types.rs +++ b/src/vm/types.rs @@ -1,7 +1,9 @@ -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug, Copy)] pub enum DmType { Int, Long, Double, Pointer, + Unit, + Exception }