diff --git a/dm_lib/std/core/array.dm b/dm_lib/std/core/array.dm index 260b51f..60650a5 100644 --- a/dm_lib/std/core/array.dm +++ b/dm_lib/std/core/array.dm @@ -1,8 +1,5 @@ ns std::core -use std::unsafe::Pointer -use std::unsafe::mem::{alloc, pointer_of) - pub int Array : Monad + Default + Empty { const default = array::empty const empty = array::empty @@ -10,42 +7,12 @@ pub int Array : Monad + Default + Empty { length: Int } -impl ArrayImpl : Array { - - fld pointer: Pointer - fld length: Int - - pub unsafe ctor(length: Int) { - self.pointer = alloc(length * T::size()) - self.length = length - } - - pub ctor(pointer: Pointer, length: Int) { - self.pointer = pointer - self.length = length - } - - pub unsafe fn set(index: Int, item: Pointer) { - pointer.offset(index * T::size()).write(item.read()) - } - -} - pub mod array { // Usage: // let int_array = array::of(1, 2, 3) // assert_eq(3, int_array.length) - pub fn of(ts: ...T): Array { - unsafe { - let array = ArrayImpl(ts.length) - for (i, t) in ts.enumerate() { - let t_pointer = pointer_of(t) - array.set(i, t_pointer) - } - array - } - } + pub extern fn of(ts: ...T): Array pub extern fn of_length(length: Int, init_value: T): Array diff --git a/dm_lib/std/unsafe/mem.dm b/dm_lib/std/unsafe/mem.dm index 60651ec..51930d5 100644 --- a/dm_lib/std/unsafe/mem.dm +++ b/dm_lib/std/unsafe/mem.dm @@ -1,14 +1 @@ ns std::unsafe - -pub int Pointer - -// Contains two fields: -// fld raw_address: Long -// fld size: Long -decl impl PointerImpl(size: Long) : Pointer - -pub mod mem { - - pub fn alloc(size: Long): Pointer = PointerImpl(size) - -} diff --git a/src/bin/dvm/main.rs b/src/bin/dvm/main.rs index 4c995a4..09e272d 100644 --- a/src/bin/dvm/main.rs +++ b/src/bin/dvm/main.rs @@ -2,9 +2,9 @@ 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_mov_const, add_mov_register_to, - add_mov_size_of, add_multiply, add_platform_call, + add_alloc, add_invoke_fn, add_mov_const, add_mov_register_to, add_platform_call, }; +use deimos::vm::platform::init_platform_functions; use deimos::vm::{call_fn, DvmContext, DvmState}; use std::rc::Rc; @@ -14,95 +14,6 @@ fn main() { // - call the main fn // fn main() { println "Hello, World!" } - // std/unsafe/mem lib - let mut mem_lib = DmLib::new("std/unsafe/mem"); - - // std::unsafe::Pointer - let pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer"); - let pointer_int_rc = Rc::new(pointer_int); - - // std::unsafe::PointerImpl : Pointer - let mut pointer_impl = DmImplementation::new( - "std::unsafe:PointerImpl", - "PointerImpl", - Some(pointer_int_rc.clone()), - ); - - let pointer_impl_raw_address = DmField::new("raw_address", DmType::Long, 0); - let pointer_impl_size = DmField::new("size", DmType::Long, 8); - - // std::unsafe::PointerImpl::_ctor_0( - // r0: self - // r1: size Long - // ) - // r2: raw_address Long - 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 pointer_impl_ctor_0_code, - 0, - pointer_impl_raw_address.data_offset() as u32, - 2, - ); - add_mov_register_to( - &mut pointer_impl_ctor_0_code, - 0, - pointer_impl_size.data_offset() as u32, - 1, - ); - - let pointer_impl_ctor_0_fn = DmFn::new( - "std::unsafe::PointerImpl::_ctor_0", - "_ctor_0", - pointer_impl_ctor_0_code, - 3, - None, - ); - - let pointer_impl_ctor_0_method = DmMethod::new(pointer_impl_ctor_0_fn, None); - - pointer_impl.fields.push(pointer_impl_raw_address); - pointer_impl.fields.push(pointer_impl_size); - pointer_impl - .methods - .push(Rc::new(pointer_impl_ctor_0_method)); - - let unsafe_pointer_impl_rc = Rc::new(pointer_impl); - - mem_lib.interfaces.push(pointer_int_rc.clone()); - mem_lib.implementations.push(unsafe_pointer_impl_rc.clone()); - - // std::unsafe::alloc( - // r0: size Long - // ) - // r0: size Long - // r1: Pointer object - // r2: Void from PointerImpl::_ctor_0 - // @return r1 - let mut alloc_fn_code: Vec = Vec::new(); - add_alloc( - &mut alloc_fn_code, - 1, - unsafe_pointer_impl_rc.size_in_bytes() as u32, - "std::unsafe::PointerImpl", - ); - add_invoke_fn( - &mut alloc_fn_code, - "std::unsafe::PointerImpl::_ctor_0", - 2, - &[1u8, 0u8], - ); - - let alloc_fn = DmFn::new( - "std::unsafe::mem::alloc", - "alloc", - alloc_fn_code, - 3, - Some(1), - ); - - mem_lib.functions.push(Rc::new(alloc_fn)); - // std/core/array lib let mut array_lib = DmLib::new("std/core/array"); @@ -117,45 +28,31 @@ fn main() { Some(array_int_rc.clone()), ); - let array_impl_pointer_fld = DmField::new("pointer", DmType::Pointer, 0); - let array_impl_length_fld = DmField::new("length", DmType::Int, 8); + let array_impl_ptr_address_fld = DmField::new("ptr_address", DmType::USize, 0); + let array_impl_ptr_size_fld = DmField::new("ptr_size", DmType::USize, 8); + let array_impl_length_fld = DmField::new("length", DmType::Long, 16); - // std::core::Array::_ctor_0( + array_impl.fields.push(array_impl_ptr_address_fld); + array_impl.fields.push(array_impl_ptr_size_fld); + array_impl.fields.push(array_impl_length_fld); + + // std::core::ArrayImpl::_ctor_0( // r0: self - // r1: TypeRef element_type - // r2: Int length + // r1: USize ptr_address + // r2: USize ptr_size + // r3: Long length // ) - // r3: r1::size() - // r4: r3 * r1 - // r5: Pointer allocated pointer let mut array_impl_ctor_0_bytecode: Vec = Vec::new(); - add_mov_size_of(&mut array_impl_ctor_0_bytecode, 3, 1); - add_multiply(&mut array_impl_ctor_0_bytecode, 4, 3, 1); - add_invoke_fn( - &mut array_impl_ctor_0_bytecode, - "std::unsafe::mem::alloc", - 5, - &[4], - ); - add_mov_register_to( - &mut array_impl_ctor_0_bytecode, - 0, - array_impl_pointer_fld.data_offset() as u32, - 5, - ); - add_mov_register_to( - &mut array_impl_ctor_0_bytecode, - 0, - array_impl_length_fld.data_offset() as u32, - 2, - ); + add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 0, 1); + add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 8, 2); + add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 16, 3); let array_impl_ctor_0_fn = DmFn::new( "std::core::ArrayImpl::_ctor_0", "_ctor_0", array_impl_ctor_0_bytecode, - 6, + 4, None, ); let array_impl_ctor_0_method = DmMethod::new(array_impl_ctor_0_fn, None); @@ -163,7 +60,8 @@ fn main() { // Add Array and ArrayImpl to array lib array_lib.interfaces.push(array_int_rc.clone()); - array_lib.implementations.push(Rc::new(array_impl)); + let array_impl_rc = Rc::new(array_impl); + array_lib.implementations.push(array_impl_rc.clone()); // std::core::String let mut string_lib = DmLib::new("std/core/string"); @@ -172,19 +70,15 @@ fn main() { let mut string_impl = DmImplementation::new("std::core::StringImpl", "StringImpl", None); - let bytes_field = DmField::new("bytes", DmType::Pointer, 0); + let bytes_field = DmField::new("bytes", DmType::Object, 0); + string_impl.fields.push(bytes_field); // std::core::String::_ctor_0( // r0: self - // r1: DvmPointer to Array + // r1: Array bytes // ) let mut string_ctor_0_bytecode: Vec = Vec::new(); - add_mov_register_to( - &mut string_ctor_0_bytecode, - 0, - bytes_field.data_offset() as u32, - 1, - ); + add_mov_register_to(&mut string_ctor_0_bytecode, 0, 0, 1); let string_ctor_0_fn = DmFn::new( "std::core::StringImpl::_ctor_0", @@ -196,7 +90,6 @@ fn main() { let string_ctor_0_method = DmMethod::new(string_ctor_0_fn, None); - 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(); @@ -207,41 +100,62 @@ fn main() { let mut greeting_lib = DmLib::new("greeting"); greeting_lib .constants - .push(DmConstant::String("Hello, World!".to_string())); + .push(DmConstant::String("Hello, Jeanna!".to_string())); let mut main_byte_code = Vec::new(); - // 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 + // Move greeting + // r0: greeting address + // r1: greeting size + add_mov_const(&mut main_byte_code, 0, 1, "greeting", 0); + + // Alloc Array greeting bytes add_alloc( &mut main_byte_code, - 0, + 2, + array_impl_rc.size_in_bytes() as u32, + "std::core::ArrayImpl", + ); + + // Call ArrayImpl(ptr_address, ptr_size, length) + add_invoke_fn( + &mut main_byte_code, + "std::core::ArrayImpl::_ctor_0", + 3, + &[2, 0, 1, 1], + ); + + // Alloc StringImpl greeting + add_alloc( + &mut main_byte_code, + 4, core_string_impl_size as u32, "std::core::StringImpl", ); - add_mov_const(&mut main_byte_code, 1, "greeting", 0); + + // Call StringImpl(greeting_bytes) add_invoke_fn( &mut main_byte_code, "std::core::StringImpl::_ctor_0", - 2, - &[0, 1], + 5, + &[4, 2], ); - add_platform_call(&mut main_byte_code, "std::core::println", 3, 1, &vec![0u8]); - let main_dm_fn = DmFn::new("main", "main", main_byte_code, 2, None); + // Call println(greeting) + add_platform_call(&mut main_byte_code, "std::core::println", 6, &[4]); + + let main_dm_fn = DmFn::new("main", "main", main_byte_code, 7, None); greeting_lib.functions.push(Rc::new(main_dm_fn)); let mut state = DvmState::new(); let mut context = DvmContext::new(); - context.load(vec![ - Rc::new(greeting_lib), - Rc::new(string_lib), - Rc::new(array_lib), - Rc::new(mem_lib) + context.load_libs(vec![ + Rc::new(greeting_lib), + Rc::new(string_lib), + Rc::new(array_lib), ]); + context.load_platform_fns(&init_platform_functions()); let main_fn = context.fn_by_fqn("main").unwrap(); call_fn(&mut state, &context, &main_fn, vec![]); diff --git a/src/util/trie.rs b/src/util/trie.rs index 43dbe67..1adf81b 100644 --- a/src/util/trie.rs +++ b/src/util/trie.rs @@ -1,49 +1,49 @@ // use crate::util::trie::GetEdgeResult::{EdgeKeyIsPrefix, EqualKeys, KeyIsPrefix}; // use std::collections::HashMap; // use std::rc::Rc; -// +// // pub struct RadixTrie { // root: RadixTrieNode, // } -// +// // struct RadixTrieNode { // edges: HashMap>, // value: Option>, // } -// +// // impl RadixTrie { // pub fn new() -> Self { // RadixTrie { // root: Default::default(), // } // } -// +// // pub fn insert(&mut self, key: &str, value: &Rc) { // self.root.insert_helper(key, value); // } -// +// // pub fn remove(&mut self, key: &str) { // todo!() // } -// +// // pub fn find(&self, key: &str) -> Option> { // todo!() // } // } -// +// // impl Default for RadixTrieNode { // fn default() -> Self { // RadixTrieNode::new() // } // } -// +// // enum GetEdgeResult<'a, T> { // EqualKeys, // KeyIsPrefix(&'a str, &'a mut RadixTrieNode), // common prefix and target node // EdgeKeyIsPrefix(&'a str, &'a mut RadixTrieNode), // non-common suffix and target node, // None, // } -// +// // impl RadixTrieNode { // fn new() -> Self { // RadixTrieNode { @@ -51,14 +51,14 @@ // value: None, // } // } -// +// // fn get_edge<'a>(&'a mut self, key: &'a str) -> GetEdgeResult<'a, T> { // for (edge_key, edge_node) in self.edges.iter_mut() { // // Case: edge_key == key: overwrite data // if *key == *edge_key { // return EqualKeys; // } -// +// // // Find how many common characters there are starting from the beginning and terminating // // as soon as there is no match // let mut i = 0; @@ -71,28 +71,28 @@ // break 'number_of_common_chars; // } // } -// +// // // Case: key's first char does not match at all: continue searching // if i == 0 { // continue; // } -// +// // // Case: key is prefix of edge_key // if i < edge_key.len() { // return KeyIsPrefix(key, edge_node); // } -// +// // if i == edge_key.len() { // panic!( // "Should not have gotten here: counted common chars equals edge_key's length." // ) // } -// +// // return EdgeKeyIsPrefix(&edge_key[i..], edge_node); // } // GetEdgeResult::None // } -// +// // fn insert_helper(&mut self, key: &str, value: &Rc) { // match self.get_edge(key) { // EqualKeys => { @@ -102,8 +102,8 @@ // KeyIsPrefix(prefix, edge_node) => { // // split like asparagus break // let old_target_node = self.edges.remove(key).unwrap(); -// -// +// +// // let mut common_prefix_node: RadixTrieNode = RadixTrieNode::new(); // } // EdgeKeyIsPrefix(suffix, edge_node) => { diff --git a/src/vm/dm_type.rs b/src/vm/dm_type.rs index 575d252..a0b9379 100644 --- a/src/vm/dm_type.rs +++ b/src/vm/dm_type.rs @@ -5,7 +5,8 @@ pub enum DmType { Long, Double, Boolean, - Pointer, + Object, + USize, Unit, } @@ -17,7 +18,8 @@ impl DmType { DmType::Long => size_of::(), DmType::Double => size_of::(), DmType::Boolean => size_of::(), - DmType::Pointer => size_of::(), + DmType::Object => size_of::(), + DmType::USize => size_of::(), DmType::Unit => todo!("Need to determine size of Unit... is it dependent on the size of the thing which is Unit?") } } diff --git a/src/vm/dvm_value.rs b/src/vm/dvm_value.rs index 3ef7971..aca7667 100644 --- a/src/vm/dvm_value.rs +++ b/src/vm/dvm_value.rs @@ -1,4 +1,4 @@ -use crate::vm::mem::DmAllocObject; +use crate::vm::object::DmAllocObject; use std::rc::Rc; #[derive(Debug, Clone, PartialEq)] @@ -8,7 +8,8 @@ pub enum DvmValue { Long(i64), Double(f64), Boolean(bool), - Pointer(Rc), + Object(Rc), + USize(usize), Uninit, Void, } @@ -18,15 +19,23 @@ impl DvmValue { if let DvmValue::Long(l) = self { *l } else { - panic!("Expected DvmValue::Long, but found {:?}", self) + panic!("Expected DvmValue::Long, but found DvmValue::{:?}", self) } } - pub fn expect_pointer(&self) -> Rc { - if let DvmValue::Pointer(p) = self { - p.clone() + pub fn expect_object(&self) -> Rc { + if let DvmValue::Object(o) = self { + o.clone() } else { - panic!("Expected DvmValue::Pointer, but found {:?}", self); + panic!("Expected DvmValue::Object, but found DvmValue::{:?}", self); + } + } + + pub fn expect_usize(&self) -> usize { + if let DvmValue::USize(u) = self { + *u + } else { + panic!("Expected DvmValue::USize, but found DvmValue::{:?}", self); } } } diff --git a/src/vm/lib/load.rs b/src/vm/lib/load.rs index aa7004b..d2730f4 100644 --- a/src/vm/lib/load.rs +++ b/src/vm/lib/load.rs @@ -1,7 +1,7 @@ use crate::get_32_le; -use crate::vm::lib::DmLib; use crate::vm::lib::magic::{CONST_SYMBOL, DEIMOS_MAGIC_NUMBER, FUNCTION_SYMBOL}; use crate::vm::lib::symbol::LibSymbol; +use crate::vm::lib::DmLib; pub fn load_module(bytes: &[u8]) -> Result { let mut ip: usize = 0; diff --git a/src/vm/lib/write.rs b/src/vm/lib/write.rs index 837a3a6..36cd9c3 100644 --- a/src/vm/lib/write.rs +++ b/src/vm/lib/write.rs @@ -1,5 +1,5 @@ -use crate::vm::lib::DmLib; use crate::vm::lib::magic::{COMPILER_VERSION_STRING, DEIMOS_MAGIC_STRING}; +use crate::vm::lib::DmLib; macro_rules! push_byte_array { ( $dest: expr, $arr: expr ) => { @@ -37,4 +37,4 @@ pub fn write_module(module: DmLib) -> Vec { push_string!(result, COMPILER_VERSION_STRING); result -} \ No newline at end of file +} diff --git a/src/vm/mem.rs b/src/vm/mem.rs index ecd7e7a..0cb8beb 100644 --- a/src/vm/mem.rs +++ b/src/vm/mem.rs @@ -1,40 +1,9 @@ use crate::vm::dm_type::DmType; use crate::vm::dvm_value::DvmValue; -use crate::vm::object_type::{DmField, DmImplementation}; -use std::alloc::{alloc, dealloc, Layout}; -use std::collections::HashSet; +use crate::vm::object::DmAllocObject; +use crate::vm::object_type::DmField; use std::rc::Rc; -#[derive(Debug, PartialEq, Eq)] -pub struct DmAllocObject { - pub data: *mut u8, - pub units: HashSet, - pub size: usize, - pub layout: Layout, - pub implementation: Rc, -} - -impl DmAllocObject { - pub fn new(size: usize, implementation: Rc) -> Self { - let layout = Layout::from_size_align(size, 1).unwrap(); - DmAllocObject { - data: unsafe { alloc(layout) }, - units: HashSet::new(), - size, - layout, - implementation, - } - } -} - -impl Drop for DmAllocObject { - fn drop(&mut self) { - unsafe { - dealloc(self.data, self.layout); - } - } -} - pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -> DvmValue { let data_size = dm_field.dm_type().size_in_bytes(); let mut raw_data: Vec = Vec::with_capacity(data_size); @@ -53,11 +22,14 @@ pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) - raw_data[0..data_size].try_into().unwrap(), )), DmType::Boolean => DvmValue::Boolean(raw_data[0] != 0), - DmType::Pointer => { + DmType::Object => { // read the pointer's (address) value let address = usize::from_ne_bytes(raw_data[0..data_size].try_into().unwrap()); - DvmValue::Pointer(Rc::from_raw(address as *const DmAllocObject)) + DvmValue::Object(Rc::from_raw(address as *const DmAllocObject)) } + DmType::USize => DvmValue::USize(usize::from_ne_bytes( + raw_data[0..data_size].try_into().unwrap(), + )), DmType::Unit => DvmValue::Uninit, } } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 112aea8..35cac1b 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -2,14 +2,16 @@ pub mod dm_type; pub mod dvm_value; pub mod lib; pub mod mem; +mod object; pub mod object_type; pub mod op_codes; pub mod platform; +mod pointer; pub mod util; use crate::vm::dvm_value::DvmValue; use crate::vm::lib::{DmConstant, DmLib}; -use crate::vm::mem::{get_field_value, DmAllocObject}; +use crate::vm::object::DmAllocObject; use crate::vm::object_type::DmFn; use op_codes::*; use std::alloc::{alloc, dealloc, Layout}; @@ -19,13 +21,15 @@ use std::rc::Rc; pub type PlatformFunction = fn(args: Vec, state: &mut DvmState, context: &DvmContext) -> DvmValue; +#[derive(Debug)] enum CallFrame { PlatformCall(CallFrameInfo), DeimosCall(CallFrameInfo), } +#[derive(Debug)] struct CallFrameInfo { - fn_fqn: String, + pub fqn: String, } pub struct DvmContext { @@ -43,7 +47,7 @@ impl DvmContext { } } - pub fn load(&mut self, libs: Vec>) { + pub fn load_libs(&mut self, libs: Vec>) { for lib in libs { self.libs.push(lib.clone()); for lib_fn in &lib.functions { @@ -75,14 +79,19 @@ impl DvmContext { .iter() .flat_map(|implementation| &implementation.methods) { - self.functions.insert( - method.dm_fn().fqn().to_string(), - method.dm_fn().clone(), - ); + self.functions + .insert(method.dm_fn().fqn().to_string(), method.dm_fn().clone()); } } } + pub fn load_platform_fns(&mut self, platform_fns: &HashMap) { + for (fqn, platform_fn) in platform_fns { + self.platform_functions + .insert(fqn.to_string(), Rc::new(*platform_fn)); + } + } + pub fn fn_by_fqn(&self, fqn: &str) -> Option> { self.functions.get(fqn).cloned() } @@ -108,6 +117,30 @@ impl DvmState { } } +macro_rules! dump_state { + ( $message: expr, $state: expr ) => { + println!("----"); + println!("{}", $message); + println!("----"); + + 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); + } + } + } + println!("Registers: "); + for (i, register) in $state.registers.iter().enumerate() { + println!(" r{}: {:?}", i, register); + } + }; +} + pub fn call_fn( state: &mut DvmState, context: &DvmContext, @@ -116,7 +149,7 @@ pub fn call_fn( ) -> DvmValue { // save current state state.call_stack.push(CallFrame::DeimosCall(CallFrameInfo { - fn_fqn: dm_fn.fqn().to_string(), + fqn: dm_fn.fqn().to_string(), })); state.register_state_stack.push(state.registers.clone()); @@ -129,8 +162,8 @@ pub fn call_fn( } // push args - for arg in args { - state.registers.push(arg); + for (i, arg) in args.iter().enumerate() { + state.registers[i] = arg.clone(); } // run the byte code @@ -233,31 +266,23 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 MOV_INT => { let target_register = next_8!(iter, usize); let operand = next_32_le!(iter, u32) as i32; - state - .registers - .insert(target_register, DvmValue::Int(operand)); + 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 - .insert(target_register, DvmValue::Long(operand)); + 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 - .insert(target_register, DvmValue::Double(operand)); + 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 = state.registers.get(source_register).unwrap(); - state - .registers - .insert(target_register, source_value.clone()) + state.registers[target_register] = source_value.clone(); } ALLOC => { let target_register = next_8!(iter, usize); @@ -275,13 +300,17 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 .expect(&format!("Implementation not found: {}", impl_name)); let dm_alloc_object = DmAllocObject::new(alloc_size, implementation.clone()); - let dvm_pointer = DvmValue::Pointer(Rc::new(dm_alloc_object)); - state.registers.insert(target_register, dvm_pointer); + state.registers[target_register] = DvmValue::Object(Rc::new(dm_alloc_object)); } 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 + .get(target_register) + .unwrap() + .expect_object(); drop(dm_alloc_object); // explicit + state.registers[target_register] = DvmValue::Uninit; } MOV_INT_TO => { let target_register = next_8!(iter, usize); @@ -292,7 +321,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 .registers .get(target_register) .unwrap() - .expect_pointer(); + .expect_object(); write_bytes!(dm_alloc_object.data, offset, operand.to_ne_bytes()); } MOV_LONG_TO => { @@ -312,7 +341,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 .registers .get(target_register) .unwrap() - .expect_pointer(); + .expect_object(); let source_value = state.registers.get(source_register).unwrap(); match source_value { @@ -331,14 +360,17 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 DvmValue::Boolean(b) => unsafe { target_alloc_object.data.add(offset).write(*b as u8); }, - DvmValue::Pointer(source_alloc_object) => { - let source_ptr = Rc::into_raw(source_alloc_object.clone()); + DvmValue::Object(source_object) => { + let source_object_ptr = Rc::into_raw(source_object.clone()); write_bytes!( target_alloc_object.data, offset, - (source_ptr as usize).to_ne_bytes() + (source_object_ptr as usize).to_ne_bytes() ); } + DvmValue::USize(us) => { + write_bytes!(target_alloc_object.data, offset, us.to_ne_bytes()); + } DvmValue::Uninit => { panic!("Cannot move DvmValue::Uninit to object.") } @@ -348,15 +380,11 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 } } MOV_CONST => { - // TODO: reduce the complexity of this. - // Perhaps the target register should just contain a ptr where the data is written. - // Decode - let target_register = next_8!(iter, usize); // must contain an allocated StringImpl + let address_register = next_8!(iter, usize); + let size_register = next_8!(iter, usize); let lib_name = read_string!(iter); - let const_id = next_8!(iter, usize); - let pointer_impl_register = next_8!(iter, usize); - let byte_array_impl_register = next_8!(iter, usize); + let const_id = next_32_le!(iter, usize); // Get constant let Some(lib) = context.libs.iter().find(|lib| lib.name == lib_name) else { @@ -365,118 +393,49 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 let constant = lib.constants.get(const_id).unwrap(); let DmConstant::String(s) = constant; - // Get allocated PointerImpl - let pointer_impl = state - .registers - .get(pointer_impl_register) - .unwrap() - .expect_pointer(); + // Alloc memory for constant + let size = s.len(); + let layout = Layout::from_size_align(size, 1).unwrap(); + let raw_pointer = unsafe { alloc(layout) }; - // Init PointerImpl object - let pointer_impl_ctor_0_fn = context - .functions - .get("std::unsafe::PointerImpl::_ctor_0") - .expect("Could not find std::unsafe::PointerImpl::_ctor_0"); - call_fn( - state, - context, - pointer_impl_ctor_0_fn, - vec![ - DvmValue::Pointer(pointer_impl.clone()), - DvmValue::Long(s.len() as i64), - ], - ); - - // Get std::unsafe::PointerImpl.raw_address field as *mut u8 - let raw_ptr = unsafe { - get_field_value( - pointer_impl - .implementation - .get_field("raw_address", &pointer_impl) - .expect("Could not get PointerImpl.raw_address field."), - &pointer_impl, - ) + // Move constant to memory + let bytes = s.as_bytes(); + for i in 0..size { + unsafe { + raw_pointer.add(i).write(bytes[i]); + } } - .expect_long() as usize as *mut u8; - // Write the constant bytes to the raw_ptr - write_string!(raw_ptr, s); - - // Get allocated ArrayImpl from byte_array_impl_register - let byte_array_impl = state - .registers - .get(byte_array_impl_register) - .unwrap() - .expect_pointer(); - - // Init ArrayImpl - let array_ctor_0_fn = context - .functions - .get("std::core::ArrayImpl::_ctor_1") - .expect("Could not find std::core::ArrayImpl::_ctor_1"); - call_fn( - state, - context, - array_ctor_0_fn, - vec![ - DvmValue::Pointer(byte_array_impl.clone()), // self - DvmValue::Pointer(pointer_impl.clone()), // PointerImpl - DvmValue::Int(s.len() as i32), // length - ], - ); - - // Get allocated StringImpl from string_impl_register - let string_impl = state - .registers - .get(target_register) - .unwrap() - .expect_pointer(); - - // Init StringImpl - let string_impl_ctor_0_fn = context - .functions - .get("std::core::StringImpl::_ctor_0") - .expect("Could not find std::core::StringImpl::_ctor_0"); - call_fn( - state, - context, - string_impl_ctor_0_fn, - vec![ - DvmValue::Pointer(string_impl.clone()), - DvmValue::Pointer(byte_array_impl.clone()), - ], - ); + // Store the pointer metadata in target registers. + state.registers[address_register] = DvmValue::USize(raw_pointer as usize); + state.registers[size_register] = DvmValue::USize(size); } ALLOC_RAW => { // Allocates a raw number of bytes, with the number of bytes determined by the value - // of the source register. The address is stored in the target register as a - // DvmValue::Long. - let target_register = next_8!(iter, usize); + // of the source register. + let address_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)) + 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 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; + // 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) + .unwrap() + .expect_usize(); + let size = state.registers.get(size_register).unwrap().expect_usize(); + let layout = Layout::from_size_align(size, 1).unwrap(); unsafe { - dealloc(ptr, layout); + dealloc(address as *mut u8, layout); } - state.registers.insert(target_register, DvmValue::Uninit); + state.registers[address_register] = DvmValue::Uninit; + state.registers[size_register] = DvmValue::Uninit; } PLATFORM_CALL => { // Calls a platform function. The result of the platform call is stored in the @@ -498,11 +457,9 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 .clone(); state .call_stack - .push(CallFrame::PlatformCall(CallFrameInfo { - fn_fqn: symbol_name, - })); + .push(CallFrame::PlatformCall(CallFrameInfo { fqn: symbol_name })); let call_result = platform_function(args, state, context); - state.registers.insert(return_register, call_result); + state.registers[return_register] = call_result; state.call_stack.pop(); } INVOKE_FN => { @@ -518,7 +475,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 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); + state.registers[return_register] = call_result; } INVOKE_VIRTUAL => { let symbol_name = read_string!(iter); @@ -531,7 +488,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 args.push(value.clone()); } - let self_obj = args.get(0).unwrap().expect_pointer(); + let self_obj = args.get(0).unwrap().expect_object(); let method = self_obj .implementation .get_method(&symbol_name, &self_obj) @@ -539,7 +496,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8 let dm_fn = method.dm_fn(); let call_result = call_fn(state, context, &dm_fn, args); - state.registers.insert(return_register, call_result); + state.registers[return_register] = call_result; } INVOKE_DYNAMIC => { unimplemented!("INVOKE_DYNAMIC is not yet supported and may never be.") diff --git a/src/vm/object.rs b/src/vm/object.rs new file mode 100644 index 0000000..6817743 --- /dev/null +++ b/src/vm/object.rs @@ -0,0 +1,34 @@ +use crate::vm::object_type::DmImplementation; +use std::alloc::{alloc, dealloc, Layout}; +use std::collections::HashSet; +use std::rc::Rc; + +#[derive(Debug, PartialEq, Eq)] +pub struct DmAllocObject { + pub data: *mut u8, + pub units: HashSet, + pub size: usize, + pub layout: Layout, + pub implementation: Rc, +} + +impl DmAllocObject { + pub fn new(size: usize, implementation: Rc) -> Self { + let layout = Layout::from_size_align(size, 1).unwrap(); + DmAllocObject { + data: unsafe { alloc(layout) }, + units: HashSet::new(), + size, + layout, + implementation, + } + } +} + +impl Drop for DmAllocObject { + fn drop(&mut self) { + unsafe { + dealloc(self.data, self.layout); + } + } +} diff --git a/src/vm/object_type.rs b/src/vm/object_type.rs index 5f209c6..f8828e5 100644 --- a/src/vm/object_type.rs +++ b/src/vm/object_type.rs @@ -1,5 +1,5 @@ use crate::vm::dm_type::DmType; -use crate::vm::mem::DmAllocObject; +use crate::vm::object::DmAllocObject; use std::fmt::Debug; use std::rc::Rc; diff --git a/src/vm/op_codes.rs b/src/vm/op_codes.rs index 50e661c..93ab3ce 100644 --- a/src/vm/op_codes.rs +++ b/src/vm/op_codes.rs @@ -75,9 +75,9 @@ pub fn add_mov_register(code: &mut Vec, target_register: u8, source_register code.push(source_register); } -pub fn add_alloc(code: &mut Vec, register: u8, size: u32, implementation_name: &str) { +pub fn add_alloc(code: &mut Vec, target_register: u8, size: u32, implementation_name: &str) { code.push(ALLOC); - code.push(register); + code.push(target_register); push_number!(code, size); push_number!(code, implementation_name.len() as u32); push_string!(code, implementation_name); @@ -113,9 +113,16 @@ pub fn add_mov_register_to( code.push(source_register); } -pub fn add_mov_const(code: &mut Vec, register: u8, lib_name: &str, const_id: u32) { +pub fn add_mov_const( + code: &mut Vec, + address_register: u8, + size_register: u8, + lib_name: &str, + const_id: u32, +) { code.push(MOV_CONST); - code.push(register); + code.push(address_register); + code.push(size_register); push_number!(code, lib_name.len() as u32); push_string!(code, lib_name); push_number!(code, const_id); @@ -125,14 +132,13 @@ pub fn add_platform_call( code: &mut Vec, symbol_name: &str, return_register: u8, - arg_registers_length: u8, - arg_registers: &Vec, + arg_registers: &[u8], ) { code.push(PLATFORM_CALL); push_number!(code, symbol_name.len() as u32); push_string!(code, symbol_name); push_number!(code, return_register); - push_number!(code, arg_registers_length); + push_number!(code, arg_registers.len() as u8); 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 a8a6f31..e11abd3 100644 --- a/src/vm/platform/std_lib/core.rs +++ b/src/vm/platform/std_lib/core.rs @@ -1,5 +1,6 @@ use crate::vm::dvm_value::DvmValue; -use crate::vm::mem::{get_field_value, DmAllocObject}; +use crate::vm::mem::get_field_value; +use crate::vm::object::DmAllocObject; use crate::vm::{DvmContext, DvmState}; use std::rc::Rc; @@ -30,14 +31,15 @@ unsafe fn get_string(dvm_value: &DvmValue) -> String { DvmValue::Long(l) => l.to_string(), DvmValue::Double(d) => d.to_string(), DvmValue::Boolean(b) => b.to_string(), - DvmValue::Pointer(object) => convert_to_string(object.clone()), + DvmValue::Object(object) => object_to_string(object.clone()), + DvmValue::USize(u) => u.to_string(), DvmValue::Uninit => String::from("Uninit"), DvmValue::Void => String::from("Void"), } } -fn convert_to_string(alloc_object_rc: Rc) -> String { - if alloc_object_rc.implementation.fqn == "std::core::String" { +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()) } else { todo!("what happens if we don't have a String?") @@ -49,36 +51,27 @@ fn extract_string_from_string(string_object: Rc) -> String { .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(); + let bytes_object = unsafe { get_field_value(&bytes_field, &string_object) }.expect_object(); if bytes_object.implementation.fqn != "std::core::ArrayImpl" { panic!("String.bytes field is not a std::core::ArrayImpl"); } - let pointer_field = bytes_object + let ptr_address_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"); - } + .get_field("ptr_address", &bytes_object) + .expect("Could not get ArrayImpl.ptr_address field."); + let address = unsafe { get_field_value(&ptr_address_field, &bytes_object) }.expect_usize(); - let raw_address_field = pointer_object + let ptr_size_field = bytes_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(); + .get_field("ptr_size", &bytes_object) + .expect("Could not get ArrayImpl.ptr_size field."); + let size = unsafe { get_field_value(&ptr_size_field, &bytes_object) }.expect_usize(); - 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 raw_bytes_pointer = address 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() }); + 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..43fc7ec --- /dev/null +++ b/src/vm/pointer.rs @@ -0,0 +1,27 @@ +use std::fmt::{Display, Formatter}; + +#[derive(Debug, PartialEq, Eq)] +pub struct DvmPointer { + address: *mut u8, + size: usize, +} + +impl DvmPointer { + pub fn new(address: *mut u8, size: usize) -> DvmPointer { + DvmPointer { address, size } + } + + pub fn address(&self) -> *mut u8 { + self.address + } + + pub fn size(&self) -> usize { + self.size + } +} + +impl Display for DvmPointer { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("0x{:x}", self.address as usize)) + } +}