From 21250ea69539995eb6c71bc8701c3ec629e2aad1 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Thu, 26 Dec 2024 14:52:08 -0600 Subject: [PATCH] Everything compiling and testing successfully. --- src/bin/dvm/main.rs | 174 +++++----- src/vm/dvm_value.rs | 3 +- src/vm/mod.rs | 571 ++++++++++---------------------- src/vm/object_type.rs | 68 ++-- src/vm/op_codes.rs | 19 +- src/vm/platform/std_lib/core.rs | 129 +++----- 6 files changed, 358 insertions(+), 606 deletions(-) diff --git a/src/bin/dvm/main.rs b/src/bin/dvm/main.rs index 5f7d16f..35a9918 100644 --- a/src/bin/dvm/main.rs +++ b/src/bin/dvm/main.rs @@ -2,11 +2,10 @@ use deimos::vm::dm_type::DmType; use deimos::vm::lib::{DmConstant, DmLib}; use deimos::vm::object_type::{DmField, DmFn, DmImplementation, DmInterface, DmMethod}; use deimos::vm::op_codes::{ - add_alloc, add_alloc_raw_from, add_invoke_fn, add_invoke_method, add_mov_const, - add_mov_register_to, add_mov_size_of, add_multiply, add_platform_call, add_ret, - add_ret_register, + add_alloc, add_alloc_raw_from, add_invoke_fn, add_mov_const, add_mov_register_to, + add_mov_size_of, add_multiply, add_platform_call, }; -use deimos::vm::DmVirtualMachine; +use deimos::vm::{call_fn, DvmContext, DvmState}; use std::rc::Rc; fn main() { @@ -16,61 +15,62 @@ fn main() { // fn main() { println "Hello, World!" } // std/unsafe/mem lib - let mut unsafe_mem_lib = DmLib::new("std/unsafe/mem"); + let mut mem_lib = DmLib::new("std/unsafe/mem"); // std::unsafe::Pointer - let unsafe_pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer"); - let unsafe_pointer_rc = Rc::new(unsafe_pointer_int); + let pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer"); + let pointer_int_rc = Rc::new(pointer_int); // std::unsafe::PointerImpl : Pointer - let mut unsafe_pointer_impl = DmImplementation::new( + let mut pointer_impl = DmImplementation::new( "std::unsafe:PointerImpl", "PointerImpl", - Some(unsafe_pointer_rc.clone()), + Some(pointer_int_rc.clone()), ); - let raw_address_field = DmField::new("raw_address", DmType::Long, 0); - let size_field = DmField::new("size", DmType::Long, 8); + let pointer_impl_raw_address = DmField::new("raw_address", DmType::Long, 0); + let pointer_impl_size = DmField::new("size", DmType::Long, 8); - // std::unsafe::Pointer::_ctor_0( + // std::unsafe::PointerImpl::_ctor_0( // r0: self // r1: size Long // ) // r2: raw_address Long - let mut unsafe_pointer_ctor_0_bytecode: Vec = Vec::new(); - add_alloc_raw_from(&mut unsafe_pointer_ctor_0_bytecode, 2, 1); + let mut pointer_impl_ctor_0_code: Vec = Vec::new(); + add_alloc_raw_from(&mut pointer_impl_ctor_0_code, 2, 1); add_mov_register_to( - &mut unsafe_pointer_ctor_0_bytecode, + &mut pointer_impl_ctor_0_code, 0, - raw_address_field.data_offset() as u32, + pointer_impl_raw_address.data_offset() as u32, 2, ); add_mov_register_to( - &mut unsafe_pointer_ctor_0_bytecode, + &mut pointer_impl_ctor_0_code, 0, - size_field.data_offset() as u32, + pointer_impl_size.data_offset() as u32, 1, ); - let unsafe_pointer_init_fn = DmFn::new( + let pointer_impl_ctor_0_fn = DmFn::new( "std::unsafe::PointerImpl::_ctor_0", "_ctor_0", - unsafe_pointer_ctor_0_bytecode, + pointer_impl_ctor_0_code, 3, + None, ); - let unsafe_pointer_init_method = DmMethod::new(unsafe_pointer_init_fn, None); + let pointer_impl_ctor_0_method = DmMethod::new(pointer_impl_ctor_0_fn, None); - unsafe_pointer_impl.fields.push(raw_address_field); - unsafe_pointer_impl.fields.push(size_field); - unsafe_pointer_impl + pointer_impl.fields.push(pointer_impl_raw_address); + pointer_impl.fields.push(pointer_impl_size); + pointer_impl .methods - .push(Rc::new(unsafe_pointer_init_method)); + .push(Rc::new(pointer_impl_ctor_0_method)); - let unsafe_pointer_impl_rc = Rc::new(unsafe_pointer_impl); + let unsafe_pointer_impl_rc = Rc::new(pointer_impl); - unsafe_mem_lib.interfaces.push(unsafe_pointer_rc.clone()); - unsafe_mem_lib + mem_lib.interfaces.push(pointer_int_rc.clone()); + mem_lib .implementations .push(unsafe_pointer_impl_rc.clone()); @@ -79,39 +79,44 @@ fn main() { // ) // r0: size Long // r1: Pointer object + // r2: Void from PointerImpl::_ctor_0 // @return r1 - let mut alloc_fn_byte_code: Vec = Vec::new(); + let mut alloc_fn_code: Vec = Vec::new(); add_alloc( - &mut alloc_fn_byte_code, + &mut alloc_fn_code, 1, unsafe_pointer_impl_rc.size_in_bytes() as u32, "std::unsafe::PointerImpl", ); - add_invoke_method( - &mut alloc_fn_byte_code, - "std::unsafe::Pointer::_ctor_0", + add_invoke_fn( + &mut alloc_fn_code, + "std::unsafe::PointerImpl::_ctor_0", + 2, &[1u8, 0u8], ); - add_ret_register(&mut alloc_fn_byte_code, 1); - let alloc_fn = DmFn { - fqn: "std::unsafe::mem::alloc".to_string(), - short_name: "alloc".to_string(), - byte_code: alloc_fn_byte_code, - number_used_registers: 2, - }; + let alloc_fn = DmFn::new( + "std::unsafe::mem::alloc", + "alloc", + alloc_fn_code, + 3, + Some(1), + ); - unsafe_mem_lib.functions.push(Rc::new(alloc_fn)); + mem_lib.functions.push(Rc::new(alloc_fn)); + + // std/core/array lib + let mut array_lib = DmLib::new("std/core/array"); // std::core::Array - let core_array_int = DmInterface::new("std::core::Array", "Array"); - let core_array_int_rc = Rc::new(core_array_int); + let array_int = DmInterface::new("std::core::Array", "Array"); + let array_int_rc = Rc::new(array_int); // std::core::ArrayImpl - let mut core_array_impl = DmImplementation::new( + let mut array_impl = DmImplementation::new( "std::core::ArrayImpl", "ArrayImpl", - Some(core_array_int_rc.clone()), + Some(array_int_rc.clone()), ); let array_impl_pointer_fld = DmField::new("pointer", DmType::Pointer, 0); @@ -153,16 +158,18 @@ fn main() { "_ctor_0", array_impl_ctor_0_bytecode, 6, + None, ); let array_impl_ctor_0_method = DmMethod::new(array_impl_ctor_0_fn, None); - core_array_impl - .methods - .push(Rc::new(array_impl_ctor_0_method)); + array_impl.methods.push(Rc::new(array_impl_ctor_0_method)); + + // Add Array and ArrayImpl to array lib + array_lib.interfaces.push(array_int_rc.clone()); + array_lib.implementations.push(Rc::new(array_impl)); // std::core::String - - let mut core_string_lib = DmLib::new("std/core/string"); - let mut core_string_impl = DmImplementation::new("std::core::String", "String", None); + let mut string_lib = DmLib::new("std/core/string"); + let mut string_impl = DmImplementation::new("std::core::String", "String", None); let bytes_field = DmField::new("bytes", DmType::Pointer, 0); @@ -170,31 +177,31 @@ fn main() { // r0: self // r1: DvmPointer to Array // ) - let mut core_string_ctor_0_bytecode: Vec = Vec::new(); + let mut string_ctor_0_bytecode: Vec = Vec::new(); add_mov_register_to( - &mut core_string_ctor_0_bytecode, + &mut string_ctor_0_bytecode, 0, bytes_field.data_offset() as u32, 1, ); - let core_string_ctor_0_fn = DmFn { - fqn: "std::core::String::_ctor_0".to_string(), - short_name: "_ctor_0".to_string(), - byte_code: core_string_ctor_0_bytecode, - number_used_registers: 2, - }; - - let core_string_ctor_0_method = DmMethod::new(core_string_ctor_0_fn, None); + let string_ctor_0_fn = DmFn::new( + "std::core::String::_ctor_0", + "_ctor_0", + string_ctor_0_bytecode, + 2, + None, + ); - core_string_impl.fields.push(bytes_field); - core_string_impl.methods.push(Rc::new(core_string_ctor_0_method)); - let core_string_impl_size = core_string_impl.size_in_bytes(); + let string_ctor_0_method = DmMethod::new(string_ctor_0_fn, None); - core_string_lib - .implementations - .push(Rc::new(core_string_impl)); + string_impl.fields.push(bytes_field); + string_impl.methods.push(Rc::new(string_ctor_0_method)); + let core_string_impl_size = string_impl.size_in_bytes(); + string_lib.implementations.push(Rc::new(string_impl)); + + // greeting lib let mut greeting_lib = DmLib::new("greeting"); greeting_lib .constants @@ -202,9 +209,9 @@ fn main() { let mut main_byte_code = Vec::new(); - // 1. Move constant: r0 receives DvmValue::Pointer to Array - // 2. Allocate for std::core::String into r1 - // 3. Call String::_ctor_0(r0) -> r2 + // 1. Move constant: r0 receives DvmValue::Pointer to ArrayImpl + // 2. Allocate for std::core::StringImpl into r1 + // 3. Call StringImpl::_ctor_0(r0) -> r2 // 4. Platform call std::core::println(r1) -> r3 add_alloc( &mut main_byte_code, @@ -213,21 +220,22 @@ fn main() { "std::core::String", ); add_mov_const(&mut main_byte_code, 1, "greeting", 0); - add_invoke_method(&mut main_byte_code, "std::core::String::_init_0", &[0, 1]); - add_platform_call(&mut main_byte_code, "std::core::println", 0, 1, &vec![0u8]); + add_invoke_fn( + &mut main_byte_code, + "std::core::StringImpl::_ctor_0", + 2, + &[0, 1], + ); + add_platform_call(&mut main_byte_code, "std::core::println", 3, 1, &vec![0u8]); - let main_dm_fn = DmFn { - fqn: "default::main".to_string(), - short_name: "main".to_string(), - byte_code: main_byte_code, - number_used_registers: 2, - }; + let main_dm_fn = DmFn::new("main", "main", main_byte_code, 2, None); greeting_lib.functions.push(Rc::new(main_dm_fn)); - let mut vm = DmVirtualMachine::new(vec![greeting_lib, core_string_lib]); - let main_fn = vm - .get_fn_by_fqn("default::main") - .expect("Could not find function: default::main"); - vm.call_fn(&main_fn, Vec::new()); + let mut state = DvmState::new(); + let mut context = DvmContext::new(); + context.load_functions(&vec![greeting_lib, string_lib, mem_lib]); + + let main_fn = context.fn_by_fqn("main").unwrap(); + call_fn(&mut state, &context, &main_fn, vec![]); } diff --git a/src/vm/dvm_value.rs b/src/vm/dvm_value.rs index 7c4730b..12dda18 100644 --- a/src/vm/dvm_value.rs +++ b/src/vm/dvm_value.rs @@ -10,6 +10,7 @@ pub enum DvmValue { Boolean(bool), Pointer(Rc), Uninit, + Void, } impl DvmValue { @@ -20,7 +21,7 @@ impl DvmValue { panic!("Expected DvmValue::long, but found {:?}", self) } } - + pub fn expect_pointer(&self) -> Rc { if let DvmValue::Pointer(p) = self { p.clone() diff --git a/src/vm/mod.rs b/src/vm/mod.rs index d156ab6..87f9ff7 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -11,14 +11,13 @@ use crate::vm::dvm_value::DvmValue; use crate::vm::lib::{DmConstant, DmLib}; use crate::vm::mem::{get_field_value, DmAllocObject}; use crate::vm::object_type::DmFn; -use crate::vm::platform::init_platform_functions; use op_codes::*; use std::alloc::{alloc, dealloc, Layout}; use std::collections::HashMap; use std::rc::Rc; -use util::{get_32_le, get_64_le}; -pub type PlatformFunction = fn(args: Vec, &mut DmVirtualMachine) -> DvmValue; +pub type PlatformFunction = + fn(args: Vec, state: &mut DvmState, context: &DvmContext) -> DvmValue; enum CallFrame { PlatformCall(CallFrameInfo), @@ -29,17 +28,6 @@ struct CallFrameInfo { fn_fqn: String, } -#[deprecated] -pub struct DmVirtualMachine { - libs: Vec, - functions: HashMap>, - platform_functions: HashMap, - ip: usize, - call_stack: Vec, - registers: Vec, - register_state_stack: Vec>, -} - pub struct DvmContext { libs: Vec, functions: HashMap>, @@ -55,6 +43,35 @@ impl DvmContext { } } + pub fn load_functions(&mut self, libs: &Vec) { + for lib in libs { + for lib_fn in &lib.functions { + self.functions + .insert(lib_fn.fqn().to_string(), lib_fn.clone()); + } + for interface_function in lib + .interfaces + .iter() + .flat_map(|interface| interface.get_functions()) + { + self.functions.insert( + interface_function.fqn().to_string(), + interface_function.clone(), + ); + } + for implementation_function in lib + .implementations + .iter() + .flat_map(|implementation| &implementation.functions) + { + self.functions.insert( + implementation_function.fqn().to_string(), + implementation_function.clone(), + ); + } + } + } + pub fn fn_by_fqn(&self, fqn: &str) -> Option> { self.functions.get(fqn).cloned() } @@ -80,40 +97,15 @@ impl DvmState { } } -fn load_functions(destination: &mut HashMap>, libs: &Vec) { - for lib in libs { - for lib_fn in &lib.functions { - destination.insert(lib_fn.fqn.clone(), lib_fn.clone()); - } - for interface_function in lib - .interfaces - .iter() - .flat_map(|interface| interface.get_functions()) - { - destination.insert(interface_function.fqn.clone(), interface_function.clone()); - } - for implementation_function in lib - .implementations - .iter() - .flat_map(|implementation| &implementation.functions) - { - destination.insert( - implementation_function.fqn.clone(), - implementation_function.clone(), - ); - } - } -} - pub fn call_fn( state: &mut DvmState, context: &DvmContext, dm_fn: &DmFn, args: Vec, -) -> Option { +) -> DvmValue { // save current state state.call_stack.push(CallFrame::DeimosCall(CallFrameInfo { - fn_fqn: dm_fn.fqn.clone(), + fn_fqn: dm_fn.fqn().to_string(), })); state.register_state_stack.push(state.registers.clone()); @@ -131,20 +123,22 @@ pub fn call_fn( } // run the byte code - run_byte_code(state, context, &dm_fn.byte_code); - - // get return value - let return_value = state - .registers - .get(dm_fn.return_register() as usize) - .map(|m| m.clone()); + run_byte_code(state, context, &dm_fn.byte_code()); // restore state state.registers = state.register_state_stack.pop().unwrap(); state.call_stack.pop(); - // return result - return_value + // get return value + if let Some(return_register) = dm_fn.return_register() { + state + .registers + .get(return_register as usize) + .map(|m| m.clone()) + .unwrap() + } else { + DvmValue::Void + } } macro_rules! next_8 { @@ -175,6 +169,19 @@ macro_rules! next_64_le { }; } +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; + } + arr + }}; +} + macro_rules! read_string { ( $iter: expr ) => {{ let str_length = next_32_le!($iter, usize); @@ -262,9 +269,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 } DEALLOC => { let target_register = next_8!(iter, usize); - let dm_alloc_object = state.registers - .remove(target_register) - .expect_pointer(); + let dm_alloc_object = state.registers.remove(target_register).expect_pointer(); drop(dm_alloc_object); // explicit } MOV_INT_TO => { @@ -326,6 +331,9 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 DvmValue::Uninit => { panic!("Cannot move DvmValue::Uninit to object.") } + DvmValue::Void => { + panic!("Cannot move DvmValue::Void to object.") + } } } MOV_CONST => { @@ -429,29 +437,101 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 ); } ALLOC_RAW => { - // Allocates a raw number of bytes, with the number of bytes determined by the - // operand - todo!() - } - ALLOC_RAW_FROM => { // Allocates a raw number of bytes, with the number of bytes determined by the value - // of the source register - todo!() + // of the source register. The address is stored in the target register as a + // DvmValue::Long. + let target_register = next_8!(iter, usize); + let source_register = next_8!(iter, usize); + let number_of_bytes = + state.registers.get(source_register).unwrap().expect_long() as usize; + let layout = Layout::from_size_align(number_of_bytes, 0).unwrap(); + let ptr = unsafe { alloc(layout) }; + state + .registers + .insert(target_register, DvmValue::Long(ptr as i64)) + } + DEALLOC_RAW => { + // Deallocates a raw number of bytes at an address, with the number of bytes + // determined by the value in the source register, and the address stored in the + // target register. + let target_register = next_8!(iter, usize); + let source_register = next_8!(iter, usize); + let number_of_bytes = + state.registers.get(source_register).unwrap().expect_long() as usize; + + let layout = Layout::from_size_align(number_of_bytes, 0).unwrap(); + let ptr = + state.registers.get(target_register).unwrap().expect_long() as usize as *mut u8; + unsafe { + dealloc(ptr, layout); + } + state.registers.insert(target_register, DvmValue::Uninit); } PLATFORM_CALL => { - todo!() + // 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() + .clone(); + state + .call_stack + .push(CallFrame::PlatformCall(CallFrameInfo { + fn_fqn: symbol_name, + })); + let call_result = platform_function(args, state, context); + state.registers.insert(return_register, call_result); + state.call_stack.pop(); } INVOKE_FN => { - todo!() + 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.functions.get(&symbol_name).unwrap(); + let call_result = call_fn(state, context, dm_fn, args); + state.registers.insert(return_register, call_result); } INVOKE_VIRTUAL => { - todo!() + 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_pointer(); + let method = self_obj + .implementation + .get_method(&symbol_name, &self_obj) + .expect(&format!("Could not find method: {}", symbol_name)); + let dm_fn = method.dm_fn(); + + let call_result = call_fn(state, context, dm_fn, args); + state.registers.insert(return_register, call_result); } INVOKE_DYNAMIC => { - todo!() - } - RETURN_REGISTER => { - todo!() + unimplemented!("INVOKE_DYNAMIC is not yet supported and may never be.") } MOV_SIZE_OF => { todo!() @@ -466,331 +546,48 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 } } -impl DmVirtualMachine { - pub fn new(libs: Vec) -> DmVirtualMachine { - let mut vm = DmVirtualMachine { - libs: libs, - functions: HashMap::new(), - platform_functions: init_platform_functions(), - ip: 0, - registers: Vec::new(), - call_stack: Vec::new(), - register_state_stack: Vec::new(), - }; - load_functions(&mut vm.functions, &vm.libs); - vm - } - - #[deprecated] - pub fn get_fn_by_fqn(&self, fqn: &str) -> Option> { - self.functions.get(fqn).cloned() - } - - #[deprecated] - pub fn call_fn(&mut self, dm_function: &DmFn, args: Vec) -> Option { - // save current state - self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame { - return_address: self.ip, - })); - self.register_state_stack.push(self.registers.clone()); - - // zero registers and make sure there are enough for dm_function - self.registers.clear(); - if self.registers.len() < args.len() { - self.registers.resize(args.len(), DvmValue::Uninit); - } - - // push args - for i in 0..args.len() { - self.registers.insert(i, args[i].clone()); - } - - // run the byte code - self.run_raw(&dm_function.byte_code); - - // restore state - 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 - self.registers.get(0).map(|x| x.clone()) - } - - pub fn run_raw(&mut self, code: &Vec) { - let mut i = 0; - while i < code.len() { - let op_code = code[i]; - println!("op_code: {:#04x}", op_code); - match code[i] { - MOV_INT => { - let target_register = code[i + 1] as usize; - let operand = next_32_le!(code, i, 2, u32); - self.registers - .insert(target_register, DvmValue::Int(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.registers - .insert(target_register, DvmValue::Long(operand as i64)); - i += 10; - } - MOV_DOUBLE => { - unimplemented!(); - } - MOV_REGISTER => { - let target_register = code[i + 1] as usize; - let source_register = code[i + 2] as usize; - let source_value = self.registers.get(source_register).unwrap(); - self.registers.insert(target_register, source_value.clone()); - i += 3; - } - ALLOC => { - i += 1; - let target_register = code[i] as usize; - i += 1; - let alloc_size = next_32_le!(code, i, 0, usize); - i += 4; - let raw_implementation_name_length = next_32_le!(code, i, 0, usize); - i += 4; - let raw_implementation_name_bytes = - code[i..(i + raw_implementation_name_length)].to_vec(); - i += raw_implementation_name_length; - let implementation_name = - String::from_utf8(raw_implementation_name_bytes).unwrap(); - - let implementation = self - .libs - .iter() - .find_map(|lib| { - lib.implementations - .iter() - .find(|implementation| implementation.fqn == implementation_name) - }) - .expect(&format!( - "Implementation not found: {}", - implementation_name - )); - - let layout = Layout::from_size_align(alloc_size, 1).unwrap(); - let raw_data_ptr; - unsafe { - raw_data_ptr = alloc(layout); - } - let dm_alloc_object = DmAllocObject { - data: raw_data_ptr, - layout, - size: alloc_size, - implementation: implementation.clone(), - }; - - let dvm_value = DvmValue::Pointer(Rc::new(dm_alloc_object)); - self.registers.insert(target_register, dvm_value); - } - DEALLOC => { - todo!() - } - MOV_INT_TO => { - todo!() - } - MOV_REGISTER_TO => { - i += 1; - let target_register = code[i] as usize; - i += 1; - let offset = next_32_le!(code, i, 0, isize); - i += 4; - let source_register = code[i] as usize; - i += 1; - - let target_value = self.registers.get(target_register).unwrap(); - let target_pointer = match target_value { - DvmValue::Pointer(alloc_object) => alloc_object.data, - _ => panic!("Expected a DvmValue::Pointer, but got: {:?}", target_value), - }; - - let source_value = self.registers.get(source_register).unwrap(); - match source_value { - DvmValue::Pointer(source_alloc_object) => unsafe { - let source_pointer = Rc::into_raw(source_alloc_object.clone()); - for (j, b) in (source_pointer as usize).to_le_bytes().iter().enumerate() - { - target_pointer.offset(offset + j as isize).write(*b); - } - }, - _ => panic!("Currently unsupported source value: {:?}", source_value), - } - } - MOV_CONST => { - i += 1; - let target_register = code[i] as usize; - i += 1; - let lib_name_length = next_32_le!(code, i, 0, usize); - i += 4; - let lib_name_raw = code[i..(i + lib_name_length)].to_vec(); - i += lib_name_length; - let const_id = next_32_le!(code, i, 0, usize); - i += 4; - - let lib_name = String::from_utf8(lib_name_raw).unwrap(); - - if let Some(lib) = self.libs.iter().find(|&lib| lib.name == lib_name) { - let constant = &lib.constants[const_id]; - match constant { - DmConstant::String(s) => { - let alloc_fn = self - .get_fn_by_fqn("std::unsafe::mem::alloc") - .expect("Could not find std::unsafe::mem::alloc"); - let alloc_size_arg = DvmValue::Long(s.len() as i64); - let alloc_return_value = - self.call_fn(&alloc_fn, vec![alloc_size_arg]).unwrap(); - let DvmValue::Pointer(pointer_object) = alloc_return_value else { - panic!("Expected std::unsafe::mem::alloc to return DvmValue::Pointer, but got: {:?}", alloc_return_value); - }; - let raw_address_field = pointer_object - .implementation - .get_field("raw_address", &pointer_object) - .expect("Could not get PointerImpl.raw_address field."); - unsafe { - let raw_address_value = - get_field_value(&raw_address_field, &pointer_object); - let DvmValue::Long(raw_address) = raw_address_value else { - panic!("Expected PointerImpl.raw_address to be a DvmValue::Long, but got: {:?}", raw_address_value); - }; - let ptr = raw_address as usize as *mut u8; - for (j, b) in s.bytes().enumerate() { - ptr.offset(j as isize).write(b); - } - self.registers - .insert(target_register, DvmValue::Pointer(pointer_object)); - } - } - _ => { - panic!("Invalid constant type"); - } - } - } else { - panic!("Could not find lib: {}", lib_name); - } - } - PLATFORM_CALL => { - i += 1; - - let symbol_name_length = next_32_le!(code, i, 0, 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 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 platform function {}", symbol_name); - } - let platform_function = platform_function_result.unwrap(); - - let call_result = platform_function(args, self); - self.registers.insert(return_register, call_result); - } - INVOKE_FN => { - unimplemented!() - } - INVOKE_VIRTUAL => { - unimplemented!(); - } - INVOKE_METHOD => { - i += 1; - let name_length = next_32_le!(code, i, 0, usize); - i += 4; - let name_raw = code[i..(i + name_length)].to_vec(); - i += name_length; - 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 method_name = String::from_utf8(name_raw).unwrap(); - - let method = self - .get_fn_by_fqn(&method_name) - .expect(&format!("Could not find method: {}", method_name)); - - let mut args: Vec = Vec::new(); - for arg_register in arg_registers { - let register_value = self.registers.get(arg_register as usize).unwrap(); - args.push(register_value.clone()); - } - - self.call_fn(method.as_ref(), args); - } - INVOKE_DYNAMIC => { - unimplemented!() - } - RETURN => { - i += 1; - } - RETURN_REGISTER => { - unimplemented!() - } - op_code => panic!("Invalid or unimplemented op code: {:#04x}", op_code), - } - } - } -} - #[cfg(test)] -mod dvm_run_tests { +mod run_code_tests { use super::*; macro_rules! assert_register { - ( $expected: expr, $register: expr ) => { - assert_eq!($expected, $register.unwrap().clone()); + ( $expected: expr, $state: expr, $register_number: expr ) => { + assert_eq!( + $expected, + $state.registers.get($register_number).unwrap().clone() + ); }; } + fn setup() -> (DvmState, DvmContext) { + (DvmState::new(), DvmContext::new()) + } + #[test] fn mov_1_as_int() { let mut code = Vec::new(); add_mov_int(&mut code, 0, 1); - let mut vm = DmVirtualMachine::new(Vec::new()); - vm.run_raw(&code); - assert_register!(DvmValue::Int(1), vm.registers.get(0)); + let (mut state, context) = setup(); + 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 vm = DmVirtualMachine::new(Vec::new()); - vm.run_raw(&code); - assert_register!(DvmValue::Int(0xffff), vm.registers.get(0)); + let (mut state, context) = setup(); + 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 vm = DmVirtualMachine::new(Vec::new()); - vm.run_raw(&code); - assert_register!(DvmValue::Int(0x0fff_ffff), vm.registers.get(0)); + let (mut state, context) = setup(); + run_byte_code(&mut state, &context, &code); + assert_register!(DvmValue::Int(0x0fff_ffff), state, 0); } #[test] @@ -798,37 +595,9 @@ 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(Vec::new()); - vm.registers.resize(2, DvmValue::Uninit); - vm.run_raw(&code); - assert_register!(DvmValue::Int(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 vm = DmVirtualMachine::new(Vec::new()); - vm.run_raw(&code); - let actual = vm.registers.get(0).unwrap().clone(); - match actual { - DvmValue::Pointer(value_box) => { - assert_eq!(DvmValue::Int(0xff), *value_box); - } - _ => 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 vm = DmVirtualMachine::new(Vec::new()); - vm.run_raw(&code); - assert_register!(DvmValue::Uninit, vm.registers.get(0)); + let (mut state, context) = setup(); + state.registers.resize(2, DvmValue::Uninit); + run_byte_code(&mut state, &context, &code); + assert_register!(DvmValue::Int(1), state, 0); } } diff --git a/src/vm/object_type.rs b/src/vm/object_type.rs index 0aaf676..73a42bd 100644 --- a/src/vm/object_type.rs +++ b/src/vm/object_type.rs @@ -11,41 +11,47 @@ pub enum DmObjectType { #[derive(Debug, Eq)] pub struct DmFn { - pub fqn: String, - pub short_name: String, - pub byte_code: Vec, - pub number_used_registers: usize, - return_register: u8 + 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: u8) -> Self { + 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 + 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) -> u8 { + + pub fn return_register(&self) -> Option { self.return_register } } @@ -74,7 +80,11 @@ impl DmMethod { dm_fn: Rc::new(dm_fn), implements, } - } + } + + pub fn dm_fn(&self) -> &DmFn { + &self.dm_fn + } } #[derive(Debug, Eq)] @@ -100,27 +110,27 @@ impl DmInterface { 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 get_functions(&self) -> Vec> { self.functions.clone() } - + pub fn add_method(&mut self, dm_virtual_method: DmVirtualMethod) { self.virtual_methods.push(Rc::new(dm_virtual_method)); } - + pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option> { if self .virtual_methods @@ -132,7 +142,7 @@ impl DmInterface { } None } - + pub fn get_virtual_methods(&self) -> Vec> { self.virtual_methods.clone() } @@ -181,7 +191,7 @@ impl DmImplementation { fields: Vec::new(), } } - + pub fn interface(&self) -> Option> { self.interface.clone() } @@ -206,7 +216,7 @@ impl DmImplementation { pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmField> { self.fields.iter().find(|field| field.name == name) } - + pub fn size_in_bytes(&self) -> usize { self.fields.iter().map(|field| field.size_in_bytes()).sum() } @@ -241,24 +251,24 @@ impl PartialEq for DmField { impl DmField { pub fn new(name: &str, dm_type: DmType, data_offset: usize) -> Self { DmField { - name: name.to_string(), + name: name.to_string(), dm_type, - data_offset + data_offset, } } - + pub fn name(&self) -> &str { &self.name } - + pub fn dm_type(&self) -> &DmType { &self.dm_type } - + pub fn data_offset(&self) -> usize { self.data_offset } - + pub fn size_in_bytes(&self) -> usize { self.dm_type.size_in_bytes() } diff --git a/src/vm/op_codes.rs b/src/vm/op_codes.rs index ffb9704..a83348e 100644 --- a/src/vm/op_codes.rs +++ b/src/vm/op_codes.rs @@ -39,16 +39,14 @@ pub const MOV_REGISTER_TO: u8 = 0x0a; pub const MOV_CONST: u8 = 0x0b; -pub const ALLOC_RAW: u8 = 0x0c; -pub const ALLOC_RAW_FROM: u8 = 0x0d; +pub const ALLOC_RAW: u8 = 0x0d; +pub const DEALLOC_RAW: u8 = 0x0e; pub const PLATFORM_CALL: u8 = 0x10; pub const INVOKE_FN: u8 = 0x11; pub const INVOKE_VIRTUAL: u8 = 0x12; pub const INVOKE_DYNAMIC: u8 = 0x14; -pub const RETURN_REGISTER: u8 = 0x21; - pub const MOV_SIZE_OF: u8 = 0x30; pub const MULTIPLY: u8 = 0x40; @@ -85,14 +83,8 @@ pub fn add_alloc(code: &mut Vec, register: u8, size: u32, implementation_nam push_string!(code, implementation_name); } -pub fn add_alloc_raw(code: &mut Vec, target_register: u8, size: u32) { - code.push(ALLOC_RAW); - code.push(target_register); - push_number!(code, size); -} - pub fn add_alloc_raw_from(code: &mut Vec, target_register: u8, source_register: u8) { - code.push(ALLOC_RAW_FROM); + code.push(ALLOC_RAW); code.push(target_register); push_number!(code, source_register); } @@ -157,11 +149,6 @@ pub fn add_invoke_fn(code: &mut Vec, fn_name: &str, return_register: u8, arg } } -pub fn add_ret_register(code: &mut Vec, register: u8) { - code.push(RETURN_REGISTER); - code.push(register); -} - pub fn add_mov_size_of(code: &mut Vec, target_register: u8, source_register: u8) { code.push(MOV_SIZE_OF); code.push(target_register); diff --git a/src/vm/platform/std_lib/core.rs b/src/vm/platform/std_lib/core.rs index da7ed8c..a8a6f31 100644 --- a/src/vm/platform/std_lib/core.rs +++ b/src/vm/platform/std_lib/core.rs @@ -1,107 +1,84 @@ use crate::vm::dvm_value::DvmValue; use crate::vm::mem::{get_field_value, DmAllocObject}; -use crate::vm::DmVirtualMachine; +use crate::vm::{DvmContext, DvmState}; use std::rc::Rc; -pub fn dm_print(args: Vec, vm: &mut DmVirtualMachine) -> DvmValue { +pub fn dm_print(args: Vec, _state: &mut DvmState, _context: &DvmContext) -> DvmValue { if args.len() != 1 { - return DvmValue::Uninit; // TODO: make exception + return DvmValue::Void; // TODO: make exception } unsafe { - print!("{}", get_string(&args[0], vm)); + print!("{}", get_string(&args[0])); } - DvmValue::Uninit + DvmValue::Void } -pub fn dm_println(args: Vec, vm: &mut DmVirtualMachine) -> DvmValue { +pub fn dm_println(args: Vec, _state: &mut DvmState, _context: &DvmContext) -> DvmValue { if args.len() != 1 { return DvmValue::Uninit; } unsafe { - println!("{}", get_string(&args[0], vm)); + println!("{}", get_string(&args[0])); } - DvmValue::Uninit + DvmValue::Void } -unsafe fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String { +unsafe fn get_string(dvm_value: &DvmValue) -> String { match dvm_value { DvmValue::Byte(b) => b.to_string(), DvmValue::Int(i) => i.to_string(), DvmValue::Long(l) => l.to_string(), DvmValue::Double(d) => d.to_string(), DvmValue::Boolean(b) => b.to_string(), - DvmValue::Pointer(alloc_object_rc) => convert_to_string(alloc_object_rc.clone(), vm), - DvmValue::Uninit => String::from("Unit"), + DvmValue::Pointer(object) => convert_to_string(object.clone()), + DvmValue::Uninit => String::from("Uninit"), + DvmValue::Void => String::from("Void"), } } -unsafe fn convert_to_string( - alloc_object_rc: Rc, - vm: &mut DmVirtualMachine, -) -> String { +fn convert_to_string(alloc_object_rc: Rc) -> String { if alloc_object_rc.implementation.fqn == "std::core::String" { - let bytes_field = alloc_object_rc - .implementation - .get_field("bytes", &alloc_object_rc) - .expect("Could not get String.bytes field."); - let bytes_value = get_field_value(&bytes_field, &alloc_object_rc); - match bytes_value { - DvmValue::Pointer(bytes_object) => { - if bytes_object.implementation.fqn == "std::core::ArrayImpl" { - let pointer_field = bytes_object - .implementation - .get_field("pointer", &bytes_object) - .expect("Could not get ArrayImpl.pointer field."); - let pointer_value = get_field_value(&pointer_field, &alloc_object_rc); - match pointer_value { - DvmValue::Pointer(pointer_object) => { - if pointer_object.implementation.fqn == "std::unsafe::PointerImpl" { - let raw_address_field = pointer_object - .implementation - .get_field("raw_address", &pointer_object) - .expect("Could not get PointerImpl.raw_address field."); - let raw_address_value = - get_field_value(raw_address_field, &alloc_object_rc); - - let size_field = pointer_object - .implementation - .get_field("size", &alloc_object_rc) - .expect("Could not get PointerImpl.size field."); - let size_value = get_field_value(&size_field, &alloc_object_rc); - let DvmValue::Long(size) = size_value else { - panic!("Expected PointerImpl.size to be a Long"); - }; - - match raw_address_value { - DvmValue::Long(raw_address) => { - let raw_bytes_pointer = raw_address as usize as *mut u8; - let mut v: Vec = Vec::new(); - for i in 0..(size as isize) { - v.push(raw_bytes_pointer.offset(i).read()); - } - String::from_utf8(v).unwrap() - } - _ => panic!("Expected raw_address to be a Long."), - } - } else { - panic!("Expected ArrayImpl.pointer to be a Pointer to PointerImpl, instead found: {:?}", pointer_object); - } - } - _ => panic!( - "Expected ArrayImpl.pointer to be a Pointer, instead found: {:?}", - pointer_value - ), - } - } else { - panic!("Expected String.bytes to be a Pointer to an ArrayImpl, instead found: {:?}", bytes_object.implementation.fqn); - } - } - _ => panic!( - "Expected String.bytes to be a Pointer, instead found: {:?}", - bytes_value - ), - } + extract_string_from_string(alloc_object_rc.clone()) } else { todo!("what happens if we don't have a String?") } } + +fn extract_string_from_string(string_object: Rc) -> String { + let bytes_field = string_object + .implementation + .get_field("bytes", &string_object) + .expect("Could not get String.bytes field."); + let bytes_object = unsafe { get_field_value(&bytes_field, &string_object) }.expect_pointer(); + if bytes_object.implementation.fqn != "std::core::ArrayImpl" { + panic!("String.bytes field is not a std::core::ArrayImpl"); + } + + let pointer_field = bytes_object + .implementation + .get_field("pointer", &bytes_object) + .expect("Could not get ArrayImpl.pointer field."); + let pointer_object = unsafe { get_field_value(&pointer_field, &bytes_object) }.expect_pointer(); + if pointer_object.implementation.fqn != "std::unsafe::PointerImpl" { + panic!("ArrayImpl.pointer is not a std::unsafe::PointerImpl"); + } + + let raw_address_field = pointer_object + .implementation + .get_field("raw_address", &pointer_object) + .expect("Could not get PointerImpl.raw_address field."); + let raw_address = unsafe { get_field_value(&raw_address_field, &pointer_object) }.expect_long(); + + let size_field = pointer_object + .implementation + .get_field("size", &pointer_object) + .expect("Could not get PointerImpl.size field."); + let size = unsafe { get_field_value(&size_field, &pointer_object) }.expect_long(); + + let raw_bytes_pointer = raw_address as usize as *mut u8; + let mut v: Vec = Vec::new(); + for i in 0..(size as isize) { + v.push(unsafe { raw_bytes_pointer.offset(i).read() }); + } + String::from_utf8(v).unwrap() +}