From 5732c4d197741a52b5eaf5df3d42925ea817b3d5 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Sat, 30 Nov 2024 16:03:22 -0600 Subject: [PATCH] All the work to print 42 via a platform call. --- src/bin/dvm/main.rs | 11 +- src/vm/mod.rs | 319 ++++++++++++-------------------- src/vm/op_codes.rs | 5 +- src/vm/platform/std_lib/core.rs | 80 ++++---- 4 files changed, 167 insertions(+), 248 deletions(-) diff --git a/src/bin/dvm/main.rs b/src/bin/dvm/main.rs index 2e87359..c2ea22b 100644 --- a/src/bin/dvm/main.rs +++ b/src/bin/dvm/main.rs @@ -1,14 +1,11 @@ -use std::process::exit; -use deimos::vm::DmVirtualMachine; use deimos::vm::op_codes::{add_mov_int, add_platform_call_to}; +use deimos::vm::DmVirtualMachine; 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]); + add_platform_call_to(&mut code, &String::from("std::core::print"), 0, 1, &vec![0u8]); let mut vm = DmVirtualMachine::new(); - if let Err(_) = vm.run(&mut code) { - eprintln!("There was an exception."); - exit(1); - } + vm.run(&mut code); + println!() } \ No newline at end of file diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 013f79f..902411d 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -12,194 +12,109 @@ use std::collections::HashMap; use std::ops::Index; use types::DmType; use util::{get_32_le, get_64_le}; +use crate::vm::DmValue::{DmInt, DmLong, DmPointer, DmUnit}; -pub type PlatformFunction = fn(PlatformCallFrame) -> Result, String>; +pub type PlatformFunction = fn(args: Vec, &mut DmVirtualMachine) -> DmValue; -enum CallFrame<'a> { - PlatformCall(PlatformCallFrame<'a>), - DeimosCall(DeimosCallFrame<'a>) +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum DmValue { + DmInt(i32), + DmLong(i64), + DmDouble(f64), + DmPointer(*mut DmObject), + DmUnit, + DmException(*mut DmObject) } -pub struct PlatformCallFrame<'a> { +enum CallFrame { + PlatformCall(PlatformCallFrame), + DeimosCall(DeimosCallFrame) +} + +pub struct PlatformCallFrame { pub name: String, pub args: Vec, pub arg_types: Vec, - pub vm: &'a mut DmVirtualMachine<'a> } -struct DeimosCallFrame<'a> { +struct DeimosCallFrame { 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> { +pub struct DmVirtualMachine { platform_functions: HashMap, ip: usize, - call_stack: Vec>, - register_set: RegisterSet, - register_state_stack: Vec, + call_stack: Vec, + registers: Vec, + register_state_stack: Vec>, } -impl DmVirtualMachine<'_> { - pub fn new<'a>() -> DmVirtualMachine<'a> { +impl DmVirtualMachine { + pub fn new() -> DmVirtualMachine { DmVirtualMachine { ip: 0, - register_set: RegisterSet::new(0), + registers: Vec::new(), platform_functions: init_platform_functions(), call_stack: Vec::new(), register_state_stack: Vec::new(), } } - pub fn call( + pub fn call( &mut self, dm_function: &DmFunction, - args: [u64; ArgLen], - arg_types: [DmType; ArgLen], - ) -> Result<(u64, DmType), String> { + args: Vec, + ) -> DmValue { // 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()); + self.register_state_stack.push(self.registers.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); + self.registers.clear(); + self.registers.resize(args.len(), DmValue::DmUnit); // 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); + self.registers.insert(i, args[i]); } // run the byte code - let call_result = self.run(&dm_function.byte_code); + self.run(&dm_function.byte_code); // restore state - self.register_set = self.register_state_stack.pop().unwrap(); + self.registers = 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)) - } + self.registers.get(0).unwrap().clone() } - pub fn run(&mut self, code: &Vec) -> Result<(), ()> { + pub fn run(&mut self, code: &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); - self.register_set.set_u32(target_register, operand, DmType::Int); + self.registers.insert(target_register, DmInt(operand as i32)); 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); + self.registers.insert(target_register, DmLong(operand as i64)); 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); + let source_value = self.registers.get(source_register).unwrap(); + self.registers.insert(target_register, source_value.clone()); i += 3; } ALLOC => { @@ -213,46 +128,49 @@ impl DmVirtualMachine<'_> { 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); + let dm_object_pointer = Box::into_raw(dm_object); + self.registers.insert(target_register, DmPointer(dm_object_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."); + let target_value = self.registers.get(target_register).unwrap(); + match target_value { + DmPointer(ptr) => unsafe { + let dm_object = Box::from_raw(ptr.clone()); + dealloc(dm_object.data, dm_object.layout); + } + _ => { + 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); + self.registers.insert(target_register, DmUnit); 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 { + let target_value = self.registers.get(target_register).unwrap(); + if let DmPointer(dm_object_ptr) = target_value { + let offset = get_32_le!(code, i, 2, isize); + let new_address = unsafe { + let dm_object = Box::from_raw(dm_object_ptr.clone()); + let data_ptr = dm_object.data; + data_ptr.offset(offset).write(code[i + 6]); + data_ptr.offset(offset + 1).write(code[i + 7]); + data_ptr.offset(offset + 2).write(code[i + 8]); + data_ptr.offset(offset + 3).write(code[i + 9]); + Box::into_raw(dm_object) + }; + self.registers.insert(target_register, DmPointer(new_address)); + i += 10; + } else { 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); + let symbol_name_length = get_32_le!(code, i, 0, usize); i += 4; let symbol_name_raw = code[i..(i + symbol_name_length)].to_vec(); @@ -260,48 +178,33 @@ impl DmVirtualMachine<'_> { let symbol_name = String::from_utf8(symbol_name_raw).unwrap(); + let return_register = code[i + 1] as usize; + i += 1; + 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 mut args = Vec::new(); + for arg_register in arg_registers { + let register_value = self.registers.get(arg_register as usize).unwrap(); + args.push(register_value.clone()); + } + let platform_function_result = self.platform_functions.get(&symbol_name); if platform_function_result.is_none() { - panic!("Unknown function {}", symbol_name); + panic!("Unknown platform 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) - } + let call_result = platform_function(args, self); + self.registers.insert(return_register, call_result); } _ => panic!("Invalid code instruction"), } } - Ok(()) } } @@ -331,75 +234,81 @@ pub struct DmObjectField { } #[cfg(test)] -mod tests { +mod dvm_run_tests { use super::*; use std::alloc::dealloc; - fn init_registers(n_registers: usize) -> (Vec, Vec) { - (vec![0; n_registers], vec![DmType::Int; n_registers]) + macro_rules! assert_register { + ( $expected: expr, $register: expr ) => { + assert_eq!($expected, $register.unwrap().clone()); + }; } #[test] fn mov_1_as_int() { let mut code = Vec::new(); add_mov_int(&mut code, 0, 1); - let (mut registers, mut register_types) = init_registers(1); - run(&code, &mut registers, &mut register_types); - assert_eq!(1, registers[0]); + let mut vm = DmVirtualMachine::new(); + vm.run(&code); + assert_register!(DmInt(1), vm.registers.get(0)); } #[test] fn move_65535_as_int() { let mut code = Vec::new(); add_mov_int(&mut code, 0, 0xffff); - let (mut registers, mut register_types) = init_registers(1); - run(&code, &mut registers, &mut register_types); - assert_eq!(0xffff, registers[0]); + let mut vm = DmVirtualMachine::new(); + vm.run(&code); + assert_register!(DmInt(0xffff), vm.registers.get(0)); } #[test] fn move_int_max_as_int() { let mut code = Vec::new(); - add_mov_int(&mut code, 0, 0xffff_ffff); - let (mut registers, mut register_types) = init_registers(1); - run(&code, &mut registers, &mut register_types); - assert_eq!(0xffff_ffff, registers[0]); + add_mov_int(&mut code, 0, 0x0fff_ffff); + let mut vm = DmVirtualMachine::new(); + vm.run(&code); + assert_register!(DmInt(0x0fff_ffff), vm.registers.get(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 registers, mut register_types) = init_registers(2); - registers[1] = 1; - run(&code, &mut registers, &mut register_types); - assert_eq!(registers[0], 1); + let mut vm = DmVirtualMachine::new(); + vm.registers.resize(2, DmUnit); + vm.run(&code); + assert_register!(DmInt(1), vm.registers.get(0)); } #[test] + #[ignore] fn mov_int_to_register_as_address() { let mut code = Vec::new(); add_alloc(&mut code, 0, 4); add_mov_int_to(&mut code, 0, 0, 0xff); - let mut registers = vec![0; 16]; - let mut register_types = vec![DmType::Int; 16]; - run(&code, &mut registers, &mut register_types); - let box_address = registers[0]; - unsafe { - let dm_object = Box::from_raw(box_address as *mut DmObject); - assert_eq!(0xff, *dm_object.data); - dealloc(dm_object.data, dm_object.layout); + let mut vm = DmVirtualMachine::new(); + vm.run(&code); + let box_address = vm.registers.get(0).unwrap().clone(); + match box_address { + DmPointer(ptr) => unsafe { + let dm_object = Box::from_raw(ptr); + assert_eq!(0xff, *dm_object.data); + dealloc(dm_object.data, dm_object.layout); + }, + _ => panic!("Target register is not a pointer"), } } #[test] + #[ignore] fn alloc_and_dealloc_expect_register_cleared() { let mut code = Vec::new(); add_alloc(&mut code, 0, 4); add_dealloc(&mut code, 0); - let (mut registers, mut register_types) = init_registers(1); - run(&code, &mut registers, &mut register_types); - assert_eq!(0, registers[0]); - assert_eq!(DmType::Int, register_types[0]); + let mut vm = DmVirtualMachine::new(); + vm.run(&code); + assert_register!(DmUnit, vm.registers.get(0)); } } diff --git a/src/vm/op_codes.rs b/src/vm/op_codes.rs index 1ff5ecf..9866c9e 100644 --- a/src/vm/op_codes.rs +++ b/src/vm/op_codes.rs @@ -81,10 +81,11 @@ 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, arg_registers_length: u8, arg_registers: &Vec) { +pub fn add_platform_call_to(code: &mut Vec, symbol_name: &String, return_register: u8, arg_registers_length: u8, arg_registers: &Vec) { code.push(PLATFORM_CALL); - push_number!(code, symbol_name.len()); + push_number!(code, symbol_name.len() as u32); push_string!(code, symbol_name); + push_number!(code, return_register); push_number!(code, arg_registers_length); for &b in arg_registers { code.push(b); diff --git a/src/vm/platform/std_lib/core.rs b/src/vm/platform/std_lib/core.rs index 3b7e052..4847092 100644 --- a/src/vm/platform/std_lib/core.rs +++ b/src/vm/platform/std_lib/core.rs @@ -1,53 +1,65 @@ use crate::vm::types::DmType; -use crate::vm::PlatformCallFrame; -use crate::vm::DmObject; +use crate::vm::DmValue::*; +use crate::vm::{DmObject, DmValue, DmVirtualMachine}; use DmType::*; +use crate::vm::module::DmFunction; -pub struct DmString { - data: String, +fn get_method<'a>(ptr: *mut DmObject, name: String) -> Option<&'a DmFunction> { + unsafe { + (*ptr).object_type.methods.get(&name) + } } -pub fn dm_print(frame: PlatformCallFrame) -> Result, String> { - if frame.args.len() != 1 { - return Err(String::from("std::core::print requires one argument.")); +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) } - match frame.arg_types[0] { - Int => { - print!("{}", frame.args[0] as i32); +} + +fn get_rust_string_from_dm_string(ptr: *mut DmObject) -> String { + unsafe { + let dm_string = Box::from_raw(ptr); + todo!() + } +} + +pub fn dm_print(args: Vec, vm: &mut DmVirtualMachine) -> DmValue { + if args.len() != 1 { + return DmException(todo!("make an Exception object.")) + } + match args[0] { + DmInt(i) => { + print!("{}", i); } - Long => { - print!("{}", frame.args[0] as i64); + DmLong(l) => { + print!("{}", l); } - Double => { - print!("{}", frame.args[0] as f64); + DmDouble(d) => { + print!("{}", d); } - Pointer => unsafe { - let dm_object = Box::from_raw(frame.args[0] as *mut DmObject); - if let Some(&ref to_string_method) = dm_object - .object_type - .methods - .get(&String::from("to_string")) - { - let call_result = frame - .vm - .call(&to_string_method, [frame.args[0]], [frame.arg_types[0]]); - if call_result.is_err() { - return Err(call_result.unwrap_err()); + DmPointer(ptr) => { + if let Some(to_string) = get_method(ptr, String::from("to_string")) { + let call_result = vm.call(&to_string, vec![args[0]]); + 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? + } } - let (dm_string_address, _) = call_result?; - // TODO: check that it's actually a DmString - let dm_string = Box::from_raw(dm_string_address as *mut DmString); - print!("{}", dm_string.data); } else { - print!("{}@{:?}", dm_object.object_type.name, dm_object.data); + print!("{}", get_rust_string_from_dm_object(ptr)); } }, - Unit => { + DmUnit => { print!("Unit") }, - Exception => { + DmException(e) => { print!("Exception") } } - Ok(None) + DmUnit }