Compare commits
	
		
			2 Commits
		
	
	
		
			d4280f40e1
			...
			6190beaed2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6190beaed2 | ||
|   | 97376bad72 | 
| @ -1,5 +1,8 @@ | ||||
| ns std::core | ||||
| 
 | ||||
| use std::unsafe::Pointer | ||||
| use std::unsafe::mem::{alloc, pointer_of) | ||||
| 
 | ||||
| pub int Array<T> : Monad + Default + Empty { | ||||
|     const default = array::empty<Self> | ||||
|     const empty = array::empty<Self> | ||||
| @ -7,12 +10,42 @@ pub int Array<T> : Monad + Default + Empty { | ||||
|     length: Int | ||||
| } | ||||
| 
 | ||||
| impl ArrayImpl<T> : Array<T> { | ||||
| 
 | ||||
|     fld pointer: Pointer<T> | ||||
|     fld length: Int | ||||
| 
 | ||||
|     pub unsafe ctor(length: Int) { | ||||
|         self.pointer = alloc(length * T::size()) | ||||
|         self.length = length | ||||
|     } | ||||
|      | ||||
|     pub ctor(pointer: Pointer<T>, length: Int) { | ||||
|         self.pointer = pointer | ||||
|         self.length = length | ||||
|     } | ||||
|      | ||||
|     pub unsafe fn set(index: Int, item: Pointer<T>) { | ||||
|         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 extern fn of<T>(ts: ...T): Array<T> | ||||
|     pub fn of<T>(ts: ...T): Array<T> { | ||||
|         unsafe { | ||||
|             let array = ArrayImpl<T>(ts.length) | ||||
|             for (i, t) in ts.enumerate() { | ||||
|                 let t_pointer = pointer_of(t) | ||||
|                 array.set(i, t_pointer) | ||||
|             } | ||||
|             array | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub extern fn of_length<T>(length: Int, init_value: T): Array<T> | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										18
									
								
								dm_lib/std/unsafe/mem.dm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								dm_lib/std/unsafe/mem.dm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| ns std::unsafe | ||||
| 
 | ||||
| pub int Pointer<T> {} | ||||
| 
 | ||||
| impl PointerImpl<T> { | ||||
| 
 | ||||
|     fld raw_address: Long | ||||
|     fld size: Long | ||||
| 
 | ||||
|     decl ctor(size: Long) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| pub mod mem { | ||||
| 
 | ||||
|     pub fn <T> alloc(size: Long): Pointer<T> = PointerImpl(size) | ||||
| 
 | ||||
| } | ||||
| @ -1,22 +1,233 @@ | ||||
| use deimos::vm::op_codes::{add_mov_int, add_platform_call_to}; | ||||
| 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, | ||||
| }; | ||||
| use deimos::vm::DmVirtualMachine; | ||||
| use deimos::vm::dvm_value::DvmValue; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| fn main() { | ||||
|     // TODO:
 | ||||
|     // - write a single module with a main()
 | ||||
|     // Goal:
 | ||||
|     // - write a single lib with a main()
 | ||||
|     // - call the main fn
 | ||||
|     
 | ||||
|     let mut code: Vec<u8> = Vec::new(); | ||||
|     add_mov_int(&mut code, 0, 0x2a); // 42
 | ||||
|     add_platform_call_to( | ||||
|         &mut code, | ||||
|         &String::from("std::core::println"), | ||||
|         0, | ||||
|         1, | ||||
|         &vec![0u8], | ||||
|     // fn main() { println "Hello, World!" }
 | ||||
| 
 | ||||
|     // std/unsafe/mem lib
 | ||||
|     let mut unsafe_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); | ||||
| 
 | ||||
|     // std::unsafe::PointerImpl : Pointer
 | ||||
|     let mut unsafe_pointer_impl = DmImplementation::new( | ||||
|         "std::unsafe:PointerImpl", | ||||
|         "PointerImpl", | ||||
|         Some(unsafe_pointer_rc.clone()), | ||||
|     ); | ||||
|     let mut vm = DmVirtualMachine::new(Vec::new()); | ||||
|     vm.run_raw(&mut code); | ||||
|     vm.call_by_fqn("default::main", vec![DvmValue::Unit; 0]); // will throw
 | ||||
| 
 | ||||
|     let raw_address_field = DmField::new("raw_address", DmType::Long, 0); | ||||
|     let size_field = DmField::new("size", DmType::Long, 8); | ||||
| 
 | ||||
|     // std::unsafe::Pointer::_ctor_0(
 | ||||
|     //   r0: self
 | ||||
|     //   r1: size Long
 | ||||
|     // )
 | ||||
|     // r2: raw_address Long
 | ||||
|     let mut unsafe_pointer_ctor_0_bytecode: Vec<u8> = Vec::new(); | ||||
|     add_alloc_raw_from(&mut unsafe_pointer_ctor_0_bytecode, 2, 1); | ||||
|     add_mov_register_to( | ||||
|         &mut unsafe_pointer_ctor_0_bytecode, | ||||
|         0, | ||||
|         raw_address_field.data_offset() as u32, | ||||
|         2, | ||||
|     ); | ||||
|     add_mov_register_to( | ||||
|         &mut unsafe_pointer_ctor_0_bytecode, | ||||
|         0, | ||||
|         size_field.data_offset() as u32, | ||||
|         1, | ||||
|     ); | ||||
| 
 | ||||
|     let unsafe_pointer_init_fn = DmFn::new( | ||||
|         "std::unsafe::PointerImpl::_ctor_0", | ||||
|         "_ctor_0", | ||||
|         unsafe_pointer_ctor_0_bytecode, | ||||
|         3, | ||||
|     ); | ||||
| 
 | ||||
|     let unsafe_pointer_init_method = DmMethod::new(unsafe_pointer_init_fn, None); | ||||
| 
 | ||||
|     unsafe_pointer_impl.fields.push(raw_address_field); | ||||
|     unsafe_pointer_impl.fields.push(size_field); | ||||
|     unsafe_pointer_impl | ||||
|         .methods | ||||
|         .push(Rc::new(unsafe_pointer_init_method)); | ||||
| 
 | ||||
|     let unsafe_pointer_impl_rc = Rc::new(unsafe_pointer_impl); | ||||
| 
 | ||||
|     unsafe_mem_lib.interfaces.push(unsafe_pointer_rc.clone()); | ||||
|     unsafe_mem_lib | ||||
|         .implementations | ||||
|         .push(unsafe_pointer_impl_rc.clone()); | ||||
| 
 | ||||
|     // std::unsafe::alloc(
 | ||||
|     //   r0: size Long
 | ||||
|     // )
 | ||||
|     // r0: size Long
 | ||||
|     // r1: Pointer object
 | ||||
|     // @return r1
 | ||||
|     let mut alloc_fn_byte_code: Vec<u8> = Vec::new(); | ||||
|     add_alloc( | ||||
|         &mut alloc_fn_byte_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", | ||||
|         &[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, | ||||
|     }; | ||||
| 
 | ||||
|     unsafe_mem_lib.functions.push(Rc::new(alloc_fn)); | ||||
| 
 | ||||
|     // std::core::Array
 | ||||
|     let core_array_int = DmInterface::new("std::core::Array", "Array"); | ||||
|     let core_array_int_rc = Rc::new(core_array_int); | ||||
| 
 | ||||
|     // std::core::ArrayImpl
 | ||||
|     let mut core_array_impl = DmImplementation::new( | ||||
|         "std::core::ArrayImpl", | ||||
|         "ArrayImpl", | ||||
|         Some(core_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); | ||||
| 
 | ||||
|     // std::core::Array::_ctor_0(
 | ||||
|     //   r0: self
 | ||||
|     //   r1: TypeRef element_type
 | ||||
|     //   r2: Int length
 | ||||
|     // )
 | ||||
|     // r3: r1::size()
 | ||||
|     // r4: r3 * r1
 | ||||
|     // r5: Pointer allocated pointer
 | ||||
|     let mut array_impl_ctor_0_bytecode: Vec<u8> = 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, | ||||
|     ); | ||||
| 
 | ||||
|     let array_impl_ctor_0_fn = DmFn::new( | ||||
|         "std::core::ArrayImpl::_ctor_0", | ||||
|         "_ctor_0", | ||||
|         array_impl_ctor_0_bytecode, | ||||
|         6, | ||||
|     ); | ||||
|     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)); | ||||
| 
 | ||||
|     // 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 bytes_field = DmField::new("bytes", DmType::Pointer, 0); | ||||
| 
 | ||||
|     // std::core::String::_ctor_0(
 | ||||
|     //   r0: self
 | ||||
|     //   r1: DvmPointer to Array<Byte>
 | ||||
|     // )
 | ||||
|     let mut core_string_ctor_0_bytecode: Vec<u8> = Vec::new(); | ||||
|     add_mov_register_to( | ||||
|         &mut core_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); | ||||
| 
 | ||||
|     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(); | ||||
| 
 | ||||
|     core_string_lib | ||||
|         .implementations | ||||
|         .push(Rc::new(core_string_impl)); | ||||
| 
 | ||||
|     let mut greeting_lib = DmLib::new("greeting"); | ||||
|     greeting_lib | ||||
|         .constants | ||||
|         .push(DmConstant::String("Hello, World!".to_string())); | ||||
| 
 | ||||
|     let mut main_byte_code = Vec::new(); | ||||
| 
 | ||||
|     // 1. Move constant: r0 receives DvmValue::Pointer to Array<Byte>
 | ||||
|     // 2. Allocate for std::core::String into r1
 | ||||
|     // 3. Call String::_ctor_0(r0) -> r2
 | ||||
|     // 4. Platform call std::core::println(r1) -> r3
 | ||||
|     add_alloc( | ||||
|         &mut main_byte_code, | ||||
|         0, | ||||
|         core_string_impl_size as u32, | ||||
|         "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]); | ||||
| 
 | ||||
|     let main_dm_fn = DmFn { | ||||
|         fqn: "default::main".to_string(), | ||||
|         short_name: "main".to_string(), | ||||
|         byte_code: main_byte_code, | ||||
|         number_used_registers: 2, | ||||
|     }; | ||||
| 
 | ||||
|     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()); | ||||
| } | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| pub mod lexer; | ||||
| pub mod parser; | ||||
| mod util; | ||||
| pub mod vm; | ||||
|  | ||||
							
								
								
									
										1
									
								
								src/util/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/util/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| pub mod trie; | ||||
							
								
								
									
										120
									
								
								src/util/trie.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/util/trie.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | ||||
| // use crate::util::trie::GetEdgeResult::{EdgeKeyIsPrefix, EqualKeys, KeyIsPrefix};
 | ||||
| // use std::collections::HashMap;
 | ||||
| // use std::rc::Rc;
 | ||||
| // 
 | ||||
| // pub struct RadixTrie<T> {
 | ||||
| //     root: RadixTrieNode<T>,
 | ||||
| // }
 | ||||
| // 
 | ||||
| // struct RadixTrieNode<T> {
 | ||||
| //     edges: HashMap<String, RadixTrieNode<T>>,
 | ||||
| //     value: Option<Rc<T>>,
 | ||||
| // }
 | ||||
| // 
 | ||||
| // impl<T> RadixTrie<T> {
 | ||||
| //     pub fn new() -> Self {
 | ||||
| //         RadixTrie {
 | ||||
| //             root: Default::default(),
 | ||||
| //         }
 | ||||
| //     }
 | ||||
| // 
 | ||||
| //     pub fn insert(&mut self, key: &str, value: &Rc<T>) {
 | ||||
| //         self.root.insert_helper(key, value);
 | ||||
| //     }
 | ||||
| // 
 | ||||
| //     pub fn remove(&mut self, key: &str) {
 | ||||
| //         todo!()
 | ||||
| //     }
 | ||||
| // 
 | ||||
| //     pub fn find(&self, key: &str) -> Option<Rc<T>> {
 | ||||
| //         todo!()
 | ||||
| //     }
 | ||||
| // }
 | ||||
| // 
 | ||||
| // impl<T> Default for RadixTrieNode<T> {
 | ||||
| //     fn default() -> Self {
 | ||||
| //         RadixTrieNode::new()
 | ||||
| //     }
 | ||||
| // }
 | ||||
| // 
 | ||||
| // enum GetEdgeResult<'a, T> {
 | ||||
| //     EqualKeys,
 | ||||
| //     KeyIsPrefix(&'a str, &'a mut RadixTrieNode<T>), // common prefix and target node
 | ||||
| //     EdgeKeyIsPrefix(&'a str, &'a mut RadixTrieNode<T>), // non-common suffix and target node,
 | ||||
| //     None,
 | ||||
| // }
 | ||||
| // 
 | ||||
| // impl<T> RadixTrieNode<T> {
 | ||||
| //     fn new() -> Self {
 | ||||
| //         RadixTrieNode {
 | ||||
| //             edges: HashMap::new(),
 | ||||
| //             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;
 | ||||
| //             'number_of_common_chars: for (key_char, edge_key_char) in
 | ||||
| //                 key.chars().zip(edge_key.chars())
 | ||||
| //             {
 | ||||
| //                 if key_char == edge_key_char {
 | ||||
| //                     i += 1;
 | ||||
| //                 } else {
 | ||||
| //                     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<T>) {
 | ||||
| //         match self.get_edge(key) {
 | ||||
| //             EqualKeys => {
 | ||||
| //                 let edge_node = self.edges.get_mut(key).unwrap();
 | ||||
| //                 edge_node.value = Some(value.clone());
 | ||||
| //             }
 | ||||
| //             KeyIsPrefix(prefix, edge_node) => {
 | ||||
| //                 // split like asparagus break
 | ||||
| //                 let old_target_node = self.edges.remove(key).unwrap();
 | ||||
| //                 
 | ||||
| //                 
 | ||||
| //                 let mut common_prefix_node: RadixTrieNode<T> = RadixTrieNode::new();
 | ||||
| //             }
 | ||||
| //             EdgeKeyIsPrefix(suffix, edge_node) => {
 | ||||
| //                 // recursive on edge_node
 | ||||
| //                 edge_node.insert_helper(suffix, value);
 | ||||
| //             }
 | ||||
| //             GetEdgeResult::None => {
 | ||||
| //                 let mut new_edge_node = RadixTrieNode::new();
 | ||||
| //                 new_edge_node.value = Some(value.clone());
 | ||||
| //                 self.edges.insert(String::from(key), new_edge_node);
 | ||||
| //             }
 | ||||
| //         }
 | ||||
| //     }
 | ||||
| // }
 | ||||
| @ -1,45 +1,24 @@ | ||||
| use std::rc::Rc; | ||||
| use crate::vm::object_type::DmObjectType; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq)] | ||||
| pub enum DmType { | ||||
|     Primitive(DmPrimitiveType), | ||||
|     Object(Rc<DmObjectType>), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq)] | ||||
| pub enum DmPrimitiveType { | ||||
|     Byte, | ||||
|     Int, | ||||
|     Long, | ||||
|     Double, | ||||
|     Boolean, | ||||
|     Pointer(Rc<DmType>), | ||||
|     ByteArray(usize), | ||||
|     IntArray(usize), | ||||
|     LongArray(usize), | ||||
|     DoubleArray(usize), | ||||
|     BooleanArray(usize), | ||||
|     PointerArray(usize, Rc<DmType>), | ||||
|     Pointer, | ||||
|     Unit, | ||||
| } | ||||
| 
 | ||||
| impl DmPrimitiveType { | ||||
| impl DmType { | ||||
|     pub fn size_in_bytes(&self) -> usize { | ||||
|         match self { | ||||
|             DmPrimitiveType::Byte => size_of::<u8>(), | ||||
|             DmPrimitiveType::Int => size_of::<i32>(), | ||||
|             DmPrimitiveType::Long => size_of::<i64>(), | ||||
|             DmPrimitiveType::Double => size_of::<f64>(), | ||||
|             DmPrimitiveType::Boolean => size_of::<bool>(), | ||||
|             DmPrimitiveType::Pointer(_) => size_of::<usize>(), | ||||
|             DmPrimitiveType::ByteArray(length) => *length * size_of::<u8>(), | ||||
|             DmPrimitiveType::IntArray(length) => *length * size_of::<i32>(), | ||||
|             DmPrimitiveType::LongArray(length) => *length * size_of::<i64>(), | ||||
|             DmPrimitiveType::DoubleArray(length) => *length * size_of::<f64>(), | ||||
|             DmPrimitiveType::BooleanArray(length) => *length * size_of::<bool>(), | ||||
|             DmPrimitiveType::PointerArray(length, _) => *length * size_of::<usize>(), | ||||
|             DmPrimitiveType::Unit => todo!("Need to determine size of Unit... is it dependent on the size of the thing which is Unit?") | ||||
|             DmType::Byte => size_of::<u8>(), | ||||
|             DmType::Int => size_of::<i32>(), | ||||
|             DmType::Long => size_of::<i64>(), | ||||
|             DmType::Double => size_of::<f64>(), | ||||
|             DmType::Boolean => size_of::<bool>(), | ||||
|             DmType::Pointer => size_of::<usize>(), | ||||
|             DmType::Unit => todo!("Need to determine size of Unit... is it dependent on the size of the thing which is Unit?") | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| use std::rc::Rc; | ||||
| use crate::vm::mem::DmAllocObject; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq)] | ||||
| pub enum DvmValue { | ||||
| @ -9,11 +9,5 @@ pub enum DvmValue { | ||||
|     Double(f64), | ||||
|     Boolean(bool), | ||||
|     Pointer(Rc<DmAllocObject>), | ||||
|     ByteArray(Vec<u8>), | ||||
|     IntArray(Vec<i32>), | ||||
|     LongArray(Vec<i64>), | ||||
|     DoubleArray(Vec<f64>), | ||||
|     BooleanArray(Vec<bool>), | ||||
|     PointerArray(Vec<Rc<DmAllocObject>>), | ||||
|     Unit, | ||||
| } | ||||
|  | ||||
| @ -1,89 +1,13 @@ | ||||
| use std::rc::Rc; | ||||
| use crate::get_32_le; | ||||
| use crate::vm::object_type::{DmFn, DmImplementation, DmInterface}; | ||||
| use crate::vm::lib::DmLib; | ||||
| use crate::vm::lib::magic::{CONST_SYMBOL, DEIMOS_MAGIC_NUMBER, FUNCTION_SYMBOL}; | ||||
| use crate::vm::lib::symbol::LibSymbol; | ||||
| 
 | ||||
| pub const DEIMOS_MAGIC_NUMBER: u64 = 0x00_00_64_65_69_6d_6f_73; // ascii 'deimos'
 | ||||
| pub const DEIMOS_MAGIC_STRING: [u8; 6] = [0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73]; // ascii 'deimos'
 | ||||
| 
 | ||||
| pub const COMPILER_VERSION_STRING: &str = "0.1.0"; | ||||
| 
 | ||||
| pub struct DmModule { | ||||
|     pub compiler_version: String, | ||||
|     pub fqn: String, | ||||
|     pub short_name: String, | ||||
|     pub constants: Vec<DmConstant>, | ||||
|     pub interfaces: Vec<Rc<DmInterface>>, | ||||
|     pub implementations: Vec<Rc<DmImplementation>>, | ||||
|     pub functions: Vec<Rc<DmFn>>, | ||||
| } | ||||
| 
 | ||||
| pub enum DmConstant { | ||||
|     Int(i32), | ||||
|     Long(i64), | ||||
|     Double(f64), | ||||
|     String(String), | ||||
| } | ||||
| 
 | ||||
| const CONST_SYMBOL: u8 = 0x01; | ||||
| const FUNCTION_SYMBOL: u8 = 0x02; | ||||
| 
 | ||||
| enum SymbolType { | ||||
|     Constant, | ||||
|     Function, | ||||
| } | ||||
| 
 | ||||
| struct DmSymbol { | ||||
|     name: String, | ||||
|     symbol_type: SymbolType, | ||||
|     address: u32, | ||||
| } | ||||
| 
 | ||||
| macro_rules! push_byte_array { | ||||
|     ( $dest: expr, $arr: expr ) => { | ||||
|         for b in $arr { | ||||
|             $dest.push(b); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| macro_rules! push_number_le { | ||||
|     ( $dest: expr, $num: expr ) => { | ||||
|         for b in $num.to_le_bytes() { | ||||
|             $dest.push(b); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| macro_rules! push_string { | ||||
|     ( $dest: expr, $s: expr ) => { | ||||
|         for b in $s.len().to_le_bytes() { | ||||
|             $dest.push(b); | ||||
|         } | ||||
|         for b in $s.bytes() { | ||||
|             $dest.push(b); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| pub fn write_module(module: DmModule) -> Vec<u8> { | ||||
|     // Push magic number
 | ||||
|     let mut result: Vec<u8> = Vec::new(); | ||||
|     push_byte_array!(result, DEIMOS_MAGIC_STRING); | ||||
| 
 | ||||
|     // Push version string
 | ||||
|     push_string!(result, module.compiler_version); | ||||
| 
 | ||||
|     // Push module name length, little endian
 | ||||
|     push_string!(result, module.fqn); | ||||
| 
 | ||||
|     result | ||||
| } | ||||
| 
 | ||||
| pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> { | ||||
| pub fn load_module(bytes: &[u8]) -> Result<DmLib, String> { | ||||
|     let mut ip: usize = 0; | ||||
|     // Check for magic number at bytes 0..5
 | ||||
|     if !check_deimos(&bytes) { | ||||
|         return Err(String::from("Not a valid Deimos module.")); | ||||
|         return Err(String::from("Not a valid Deimos lib.")); | ||||
|     } | ||||
|     ip = 6; | ||||
| 
 | ||||
| @ -103,13 +27,13 @@ pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> { | ||||
|     // Check version string. We'll use this in the future to not load modules compiled later than
 | ||||
|     // current version.
 | ||||
|     if version_string != "0.1.0" { | ||||
|         return Err(String::from("Invalid Deimos module version.")); | ||||
|         return Err(String::from("Invalid Deimos lib version.")); | ||||
|     } | ||||
| 
 | ||||
|     // TODO: extract module name
 | ||||
|     // TODO: extract lib name
 | ||||
| 
 | ||||
|     // Holder for Symbols we will extract from the symbol table bytes
 | ||||
|     let mut symbols: Vec<DmSymbol> = Vec::new(); | ||||
|     let mut symbols: Vec<LibSymbol> = Vec::new(); | ||||
| 
 | ||||
|     // Get the symbol table length and calculate how far we need to read
 | ||||
|     let symbol_table_length = get_32_le!(bytes, 10 + version_string_length, 0, usize); | ||||
| @ -118,7 +42,7 @@ pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> { | ||||
|     // For each "row" in the symbol table,
 | ||||
|     // 1. Get the type
 | ||||
|     // 2. Obtain the name's length and then get the name in utf8
 | ||||
|     // 3. Grab the address to the actual symbol in the module bytes
 | ||||
|     // 3. Grab the address to the actual symbol in the lib bytes
 | ||||
|     while ip < symbol_table_end { | ||||
|         let type_byte = bytes[ip]; | ||||
|         ip += 1; | ||||
| @ -129,16 +53,12 @@ pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> { | ||||
|         ip += name_string_length; | ||||
|         let address = get_32_le!(bytes, ip, 0, u32); | ||||
|         ip += 4; | ||||
|         let symbol_type = match type_byte { | ||||
|             CONST_SYMBOL => SymbolType::Constant, | ||||
|             FUNCTION_SYMBOL => SymbolType::Function, | ||||
|         let lib_symbol = match type_byte { | ||||
|             CONST_SYMBOL => LibSymbol::Constant(name, address), | ||||
|             FUNCTION_SYMBOL => LibSymbol::Function(name, address), | ||||
|             _ => return Err(String::from("Invalid Deimos symbol type.")), | ||||
|         }; | ||||
|         symbols.push(DmSymbol { | ||||
|             name, | ||||
|             address, | ||||
|             symbol_type, | ||||
|         }); | ||||
|         symbols.push(lib_symbol); | ||||
|     } | ||||
| 
 | ||||
|     todo!() | ||||
| @ -163,7 +83,7 @@ fn read_as_u64(bytes: &[u8]) -> u64 { | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod read_as_u64_tests { | ||||
|     use crate::vm::module::{read_as_u64, DEIMOS_MAGIC_NUMBER}; | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn read_6_bytes() { | ||||
							
								
								
									
										7
									
								
								src/vm/lib/magic.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/vm/lib/magic.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| pub const DEIMOS_MAGIC_NUMBER: u64 = 0x00_00_64_65_69_6d_6f_73; // ascii 'deimos'
 | ||||
| pub const DEIMOS_MAGIC_STRING: [u8; 6] = [0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73]; // ascii 'deimos'
 | ||||
| 
 | ||||
| pub const COMPILER_VERSION_STRING: &str = "0.1.0"; | ||||
| 
 | ||||
| pub const CONST_SYMBOL: u8 = 0x01; | ||||
| pub const FUNCTION_SYMBOL: u8 = 0x02; | ||||
							
								
								
									
										31
									
								
								src/vm/lib/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/vm/lib/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| mod load; | ||||
| mod magic; | ||||
| mod symbol; | ||||
| mod write; | ||||
| 
 | ||||
| use crate::vm::object_type::{DmFn, DmImplementation, DmInterface}; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| pub struct DmLib { | ||||
|     pub name: String, | ||||
|     pub constants: Vec<DmConstant>, | ||||
|     pub interfaces: Vec<Rc<DmInterface>>, | ||||
|     pub implementations: Vec<Rc<DmImplementation>>, | ||||
|     pub functions: Vec<Rc<DmFn>>, | ||||
| } | ||||
| 
 | ||||
| impl DmLib { | ||||
|     pub fn new(name: &str) -> DmLib { | ||||
|         DmLib { | ||||
|             name: name.to_string(), | ||||
|             constants: Vec::new(), | ||||
|             interfaces: Vec::new(), | ||||
|             implementations: Vec::new(), | ||||
|             functions: Vec::new(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub enum DmConstant { | ||||
|     String(String), | ||||
| } | ||||
							
								
								
									
										4
									
								
								src/vm/lib/symbol.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/vm/lib/symbol.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| pub enum LibSymbol { | ||||
|     Constant(String, u32), | ||||
|     Function(String, u32), | ||||
| } | ||||
							
								
								
									
										40
									
								
								src/vm/lib/write.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/vm/lib/write.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| use crate::vm::lib::DmLib; | ||||
| use crate::vm::lib::magic::{COMPILER_VERSION_STRING, DEIMOS_MAGIC_STRING}; | ||||
| 
 | ||||
| macro_rules! push_byte_array { | ||||
|     ( $dest: expr, $arr: expr ) => { | ||||
|         for b in $arr { | ||||
|             $dest.push(b); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| macro_rules! push_number_le { | ||||
|     ( $dest: expr, $num: expr ) => { | ||||
|         for b in $num.to_le_bytes() { | ||||
|             $dest.push(b); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| macro_rules! push_string { | ||||
|     ( $dest: expr, $s: expr ) => { | ||||
|         for b in $s.len().to_le_bytes() { | ||||
|             $dest.push(b); | ||||
|         } | ||||
|         for b in $s.bytes() { | ||||
|             $dest.push(b); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| pub fn write_module(module: DmLib) -> Vec<u8> { | ||||
|     // Push magic number
 | ||||
|     let mut result: Vec<u8> = Vec::new(); | ||||
|     push_byte_array!(result, DEIMOS_MAGIC_STRING); | ||||
| 
 | ||||
|     // Push version string
 | ||||
|     push_string!(result, COMPILER_VERSION_STRING); | ||||
| 
 | ||||
|     result | ||||
| } | ||||
| @ -1,7 +1,6 @@ | ||||
| use crate::vm::dm_type::DmPrimitiveType; | ||||
| use crate::vm::dm_type::DmType; | ||||
| use crate::vm::dvm_value::DvmValue; | ||||
| use crate::vm::object_type::DmImplementation; | ||||
| use crate::vm::object_type::DmProperty; | ||||
| use crate::vm::object_type::{DmField, DmImplementation}; | ||||
| use std::alloc::Layout; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| @ -13,48 +12,30 @@ pub struct DmAllocObject { | ||||
|     pub implementation: Rc<DmImplementation>, | ||||
| } | ||||
| 
 | ||||
| pub unsafe fn get_property_value( | ||||
|     dm_property: &DmProperty, | ||||
|     self_object: &DmAllocObject, | ||||
| ) -> DvmValue { | ||||
|     let data_size = dm_property.primitive_type.size_in_bytes(); | ||||
| 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<u8> = Vec::with_capacity(data_size); | ||||
|     for i in dm_property.data_offset..(dm_property.data_offset + data_size) { | ||||
|     for i in dm_field.data_offset()..(dm_field.data_offset() + data_size) { | ||||
|         raw_data.push(self_object.data.offset(i as isize).read()); | ||||
|     } | ||||
|     match dm_property.primitive_type.as_ref() { | ||||
|         DmPrimitiveType::Byte => DvmValue::Byte(raw_data[0]), | ||||
|         DmPrimitiveType::Int => DvmValue::Int(i32::from_ne_bytes( | ||||
|     match dm_field.dm_type() { | ||||
|         DmType::Byte => DvmValue::Byte(raw_data[0]), | ||||
|         DmType::Int => DvmValue::Int(i32::from_ne_bytes( | ||||
|             raw_data[0..data_size].try_into().unwrap(), | ||||
|         )), | ||||
|         DmPrimitiveType::Long => DvmValue::Long(i64::from_ne_bytes( | ||||
|         DmType::Long => DvmValue::Long(i64::from_ne_bytes( | ||||
|             raw_data[0..data_size].try_into().unwrap(), | ||||
|         )), | ||||
|         DmPrimitiveType::Double => DvmValue::Double(f64::from_ne_bytes( | ||||
|         DmType::Double => DvmValue::Double(f64::from_ne_bytes( | ||||
|             raw_data[0..data_size].try_into().unwrap(), | ||||
|         )), | ||||
|         DmPrimitiveType::Boolean => DvmValue::Boolean(raw_data[0] == 1), | ||||
|         DmPrimitiveType::Pointer(_) => { | ||||
|         DmType::Boolean => DvmValue::Boolean(raw_data[0] == 1), | ||||
|         DmType::Pointer => { | ||||
|             // 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)) | ||||
|         } | ||||
|         DmPrimitiveType::ByteArray(_) => DvmValue::ByteArray(raw_data), | ||||
|         DmPrimitiveType::IntArray(length) => DvmValue::IntArray(read_i32_array(&raw_data, *length)), | ||||
|         DmPrimitiveType::LongArray(length) => { | ||||
|             DvmValue::LongArray(read_i64_array(&raw_data, *length)) | ||||
|         } | ||||
|         DmPrimitiveType::DoubleArray(length) => { | ||||
|             DvmValue::DoubleArray(read_f64_array(&raw_data, *length)) | ||||
|         } | ||||
|         DmPrimitiveType::BooleanArray(length) => DvmValue::BooleanArray(read_bool_array(&raw_data)), | ||||
|         DmPrimitiveType::PointerArray(length, _) => DvmValue::PointerArray( | ||||
|             read_usize_array(&raw_data, *length) | ||||
|                 .iter() | ||||
|                 .map(|raw_usize| Rc::from_raw(*raw_usize as *const DmAllocObject)) | ||||
|                 .collect(), | ||||
|         ), | ||||
|         DmPrimitiveType::Unit => DvmValue::Unit, | ||||
|         DmType::Unit => DvmValue::Unit, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										226
									
								
								src/vm/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										226
									
								
								src/vm/mod.rs
									
									
									
									
									
								
							| @ -1,17 +1,19 @@ | ||||
| pub mod dm_type; | ||||
| pub mod dvm_value; | ||||
| mod mem; | ||||
| pub mod module; | ||||
| mod object_type; | ||||
| pub mod lib; | ||||
| pub mod mem; | ||||
| pub mod object_type; | ||||
| pub mod op_codes; | ||||
| pub mod platform; | ||||
| pub mod util; | ||||
| 
 | ||||
| use crate::vm::dvm_value::DvmValue; | ||||
| use crate::vm::module::DmModule; | ||||
| 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, Layout}; | ||||
| use std::collections::HashMap; | ||||
| use std::rc::Rc; | ||||
| use util::{get_32_le, get_64_le}; | ||||
| @ -33,7 +35,7 @@ struct DeimosCallFrame { | ||||
| } | ||||
| 
 | ||||
| pub struct DmVirtualMachine { | ||||
|     modules: Vec<DmModule>, | ||||
|     libs: Vec<DmLib>, | ||||
|     functions: HashMap<String, Rc<DmFn>>, | ||||
|     platform_functions: HashMap<String, PlatformFunction>, | ||||
|     ip: usize, | ||||
| @ -42,35 +44,51 @@ pub struct DmVirtualMachine { | ||||
|     register_state_stack: Vec<Vec<DvmValue>>, | ||||
| } | ||||
| 
 | ||||
| fn load_functions(modules: &Vec<DmModule>) -> HashMap<String, Rc<DmFn>> { | ||||
|     let mut functions: HashMap<String, Rc<DmFn>> = HashMap::new(); | ||||
|     for module in modules { | ||||
|         for module_fn in &module.functions { | ||||
|             functions.insert(module_fn.fqn.clone(), module_fn.clone()); | ||||
| fn load_functions(destination: &mut HashMap<String, Rc<DmFn>>, libs: &Vec<DmLib>) { | ||||
|     for module in libs { | ||||
|         for lib_fn in &module.functions { | ||||
|             destination.insert(lib_fn.fqn.clone(), lib_fn.clone()); | ||||
|         } | ||||
|         for interface_function in module | ||||
|             .interfaces | ||||
|             .iter() | ||||
|             .flat_map(|interface| interface.get_functions()) | ||||
|         { | ||||
|             destination.insert(interface_function.fqn.clone(), interface_function.clone()); | ||||
|         } | ||||
|         for implementation_function in module | ||||
|             .implementations | ||||
|             .iter() | ||||
|             .flat_map(|implementation| &implementation.functions) | ||||
|         { | ||||
|             destination.insert( | ||||
|                 implementation_function.fqn.clone(), | ||||
|                 implementation_function.clone(), | ||||
|             ); | ||||
|         } | ||||
|         for interface in &module.interfaces {} | ||||
|     } | ||||
|     functions | ||||
| } | ||||
| 
 | ||||
| impl DmVirtualMachine { | ||||
|     pub fn new(modules: Vec<DmModule>) -> DmVirtualMachine { | ||||
|         DmVirtualMachine { | ||||
|             modules, | ||||
|     pub fn new(libs: Vec<DmLib>) -> 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 | ||||
|     } | ||||
| 
 | ||||
|     pub fn call_by_fqn(&mut self, fn_fqn: &str, args: Vec<DvmValue>) -> DvmValue { | ||||
|         todo!() | ||||
|     pub fn get_fn_by_fqn(&self, fqn: &str) -> Option<Rc<DmFn>> { | ||||
|         self.functions.get(fqn).cloned() | ||||
|     } | ||||
| 
 | ||||
|     pub fn call_fn(&mut self, dm_function: &DmFn, args: Vec<DvmValue>) -> DvmValue { | ||||
|     pub fn call_fn(&mut self, dm_function: &DmFn, args: Vec<DvmValue>) -> Option<DvmValue> { | ||||
|         // save current state
 | ||||
|         self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame { | ||||
|             return_address: self.ip, | ||||
| @ -79,7 +97,9 @@ impl DmVirtualMachine { | ||||
| 
 | ||||
|         // zero registers and make sure there are enough for dm_function
 | ||||
|         self.registers.clear(); | ||||
|         self.registers.resize(args.len(), DvmValue::Unit); | ||||
|         if self.registers.len() < args.len() { | ||||
|             self.registers.resize(args.len(), DvmValue::Unit); | ||||
|         } | ||||
| 
 | ||||
|         // push args
 | ||||
|         for i in 0..args.len() { | ||||
| @ -96,12 +116,14 @@ impl DmVirtualMachine { | ||||
|         } | ||||
| 
 | ||||
|         // return result
 | ||||
|         self.registers.get(0).unwrap().clone() | ||||
|         self.registers.get(0).map(|x| x.clone()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn run_raw(&mut self, code: &Vec<u8>) { | ||||
|         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; | ||||
| @ -117,7 +139,9 @@ impl DmVirtualMachine { | ||||
|                         .insert(target_register, DvmValue::Long(operand as i64)); | ||||
|                     i += 10; | ||||
|                 } | ||||
|                 MOV_DOUBLE => { /* todo */ } | ||||
|                 MOV_DOUBLE => { | ||||
|                     unimplemented!(); | ||||
|                 } | ||||
|                 MOV_REGISTER => { | ||||
|                     let target_register = code[i + 1] as usize; | ||||
|                     let source_register = code[i + 2] as usize; | ||||
| @ -126,7 +150,46 @@ impl DmVirtualMachine { | ||||
|                     i += 3; | ||||
|                 } | ||||
|                 ALLOC => { | ||||
|                     todo!() | ||||
|                     i += 1; | ||||
|                     let target_register = code[i] as usize; | ||||
|                     i += 1; | ||||
|                     let alloc_size = get_32_le!(code, i, 0, usize); | ||||
|                     i += 4; | ||||
|                     let raw_implementation_name_length = get_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!() | ||||
| @ -134,6 +197,79 @@ impl DmVirtualMachine { | ||||
|                 MOV_INT_TO => { | ||||
|                     todo!() | ||||
|                 } | ||||
|                 MOV_REGISTER_TO => { | ||||
|                     i += 1; | ||||
|                     let target_register = code[i] as usize; | ||||
|                     i += 1; | ||||
|                     let offset = get_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 = get_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 = get_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; | ||||
| 
 | ||||
| @ -169,7 +305,47 @@ impl DmVirtualMachine { | ||||
|                     let call_result = platform_function(args, self); | ||||
|                     self.registers.insert(return_register, call_result); | ||||
|                 } | ||||
|                 _ => panic!("Invalid code instruction"), | ||||
|                 INVOKE_FN => { | ||||
|                     unimplemented!() | ||||
|                 } | ||||
|                 INVOKE_VIRTUAL => { | ||||
|                     unimplemented!(); | ||||
|                 } | ||||
|                 INVOKE_METHOD => { | ||||
|                     i += 1; | ||||
|                     let name_length = get_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<DvmValue> = 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), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -224,6 +400,7 @@ mod dvm_run_tests { | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     #[ignore] | ||||
|     fn mov_int_to_register_as_address() { | ||||
|         let mut code = Vec::new(); | ||||
|         add_alloc(&mut code, 0, 4); | ||||
| @ -240,6 +417,7 @@ mod dvm_run_tests { | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     #[ignore] | ||||
|     fn alloc_and_dealloc_expect_register_cleared() { | ||||
|         let mut code = Vec::new(); | ||||
|         add_alloc(&mut code, 0, 4); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::vm::dm_type::DmPrimitiveType; | ||||
| use crate::vm::dm_type::DmType; | ||||
| use crate::vm::mem::DmAllocObject; | ||||
| use std::fmt::Debug; | ||||
| use std::rc::Rc; | ||||
| @ -13,9 +13,35 @@ pub enum DmObjectType { | ||||
| pub struct DmFn { | ||||
|     pub fqn: String, | ||||
|     pub short_name: String, | ||||
|     pub implements: Option<DmVirtualMethod>, | ||||
|     pub byte_code: Vec<u8>, | ||||
|     pub num_registers: usize, | ||||
|     pub number_used_registers: usize, | ||||
| } | ||||
| 
 | ||||
| impl DmFn { | ||||
|     pub fn new(fqn: &str, short_name: &str, byte_code: Vec<u8>, number_used_registers: usize) -> Self { | ||||
|         DmFn { | ||||
|             fqn: fqn.to_string(), | ||||
|             short_name: short_name.to_string(), | ||||
|             byte_code, | ||||
|             number_used_registers | ||||
|         } | ||||
|     } | ||||
|     
 | ||||
|     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<u8> { | ||||
|         &self.byte_code | ||||
|     } | ||||
|     
 | ||||
|     pub fn number_used_registers(&self) -> usize { | ||||
|         self.number_used_registers | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for DmFn { | ||||
| @ -24,13 +50,33 @@ impl PartialEq for DmFn { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Eq)] | ||||
| pub struct DmMethod { | ||||
|     dm_fn: Rc<DmFn>, | ||||
|     implements: Option<Rc<DmVirtualMethod>>, | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for DmMethod { | ||||
|     fn eq(&self, other: &Self) -> bool { | ||||
|         self.dm_fn == other.dm_fn | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl DmMethod { | ||||
|     pub fn new(dm_fn: DmFn, implements: Option<Rc<DmVirtualMethod>>) -> Self { | ||||
|         DmMethod { | ||||
|             dm_fn: Rc::new(dm_fn), | ||||
|             implements, | ||||
|         } | ||||
|     }    
 | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Eq)] | ||||
| pub struct DmInterface { | ||||
|     pub fqn: String, | ||||
|     fqn: String, | ||||
|     short_name: String, | ||||
|     properties: Vec<Rc<DmProperty>>, | ||||
|     functions: Vec<Rc<DmFn>>, | ||||
|     virtual_methods: Vec<Rc<DmVirtualMethod>>, | ||||
|     impl_methods: Vec<Rc<DmFn>>, | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for DmInterface { | ||||
| @ -40,10 +86,37 @@ impl PartialEq for DmInterface { | ||||
| } | ||||
| 
 | ||||
| impl DmInterface { | ||||
|     pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmFn>> { | ||||
|         if let Some(dm_fn) = self.impl_methods.iter().find(|&dm_fn| dm_fn.fqn == name) { | ||||
|             return Some(dm_fn.clone()); | ||||
|         } else if self | ||||
|     pub fn new(fqn: &str, short_name: &str) -> Self { | ||||
|         DmInterface { | ||||
|             fqn: fqn.to_string(), | ||||
|             short_name: short_name.to_string(), | ||||
|             functions: Vec::new(), | ||||
|             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<Rc<DmFn>> { | ||||
|         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<Rc<DmMethod>> { | ||||
|         if self | ||||
|             .virtual_methods | ||||
|             .iter() | ||||
|             .find(|&dm_fn| dm_fn.fqn == name) | ||||
| @ -53,6 +126,10 @@ impl DmInterface { | ||||
|         } | ||||
|         None | ||||
|     } | ||||
|     
 | ||||
|     pub fn get_virtual_methods(&self) -> Vec<Rc<DmVirtualMethod>> { | ||||
|         self.virtual_methods.clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmProperty> { | ||||
|         todo!() | ||||
| @ -75,11 +152,10 @@ impl PartialEq for DmVirtualMethod { | ||||
| pub struct DmImplementation { | ||||
|     pub fqn: String, | ||||
|     pub short_name: String, | ||||
|     pub interface: Rc<DmInterface>, | ||||
|     pub size_in_bytes: usize, | ||||
|     properties: Vec<DmProperty>, | ||||
|     fields: Vec<DmField>, | ||||
|     methods: Vec<Rc<DmFn>>, | ||||
|     pub interface: Option<Rc<DmInterface>>, | ||||
|     pub functions: Vec<Rc<DmFn>>, | ||||
|     pub methods: Vec<Rc<DmMethod>>, | ||||
|     pub fields: Vec<DmField>, | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for DmImplementation { | ||||
| @ -89,9 +165,24 @@ impl PartialEq for DmImplementation { | ||||
| } | ||||
| 
 | ||||
| impl DmImplementation { | ||||
|     pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmFn>> { | ||||
|     pub fn new(fqn: &str, short_name: &str, interface: Option<Rc<DmInterface>>) -> Self { | ||||
|         DmImplementation { | ||||
|             fqn: fqn.to_string(), | ||||
|             short_name: short_name.to_string(), | ||||
|             interface, | ||||
|             functions: Vec::new(), | ||||
|             methods: Vec::new(), | ||||
|             fields: Vec::new(), | ||||
|         } | ||||
|     } | ||||
|     
 | ||||
|     pub fn interface(&self) -> Option<Rc<DmInterface>> { | ||||
|         self.interface.clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmMethod>> { | ||||
|         for method in &self.methods { | ||||
|             if method.fqn == name { | ||||
|             if method.dm_fn.fqn == name { | ||||
|                 return Some(method.clone()); | ||||
|             } else if let Some(implements) = &method.implements { | ||||
|                 if implements.fqn == name { | ||||
| @ -106,8 +197,12 @@ impl DmImplementation { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmField>> { | ||||
|         todo!() | ||||
|     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() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -115,7 +210,7 @@ impl DmImplementation { | ||||
| pub struct DmProperty { | ||||
|     pub name: String, | ||||
|     pub data_offset: usize, | ||||
|     pub primitive_type: Rc<DmPrimitiveType>, | ||||
|     pub primitive_type: Rc<DmType>, | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for DmProperty { | ||||
| @ -127,7 +222,8 @@ impl PartialEq for DmProperty { | ||||
| #[derive(Debug, Eq)] | ||||
| pub struct DmField { | ||||
|     name: String, | ||||
|     primitive_type: Rc<DmPrimitiveType>, | ||||
|     dm_type: DmType, | ||||
|     data_offset: usize, | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for DmField { | ||||
| @ -135,3 +231,29 @@ impl PartialEq for DmField { | ||||
|         self.name == other.name | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl DmField { | ||||
|     pub fn new(name: &str, dm_type: DmType, data_offset: usize) -> Self { | ||||
|         DmField { | ||||
|             name: name.to_string(), 
 | ||||
|             dm_type, | ||||
|             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() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -37,7 +37,23 @@ pub const MOV_LONG_TO: u8 = 0x08; | ||||
| pub const MOV_DOUBLE_TO: u8 = 0x09; | ||||
| 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 PLATFORM_CALL: u8 = 0x10; | ||||
| pub const INVOKE_FN: u8 = 0x11; | ||||
| pub const INVOKE_VIRTUAL: u8 = 0x12; | ||||
| pub const INVOKE_METHOD: u8 = 0x13; | ||||
| pub const INVOKE_DYNAMIC: u8 = 0x14; | ||||
| 
 | ||||
| pub const RETURN: u8 = 0x20; | ||||
| pub const RETURN_REGISTER: u8 = 0x21; | ||||
| 
 | ||||
| pub const MOV_SIZE_OF: u8 = 0x30; | ||||
| 
 | ||||
| pub const MULTIPLY: u8 = 0x40; | ||||
| 
 | ||||
| macro_rules! push_number { | ||||
|     ( $dest: expr, $num: expr ) => { | ||||
| @ -63,10 +79,24 @@ pub fn add_mov_register(code: &mut Vec<u8>, target_register: u8, source_register | ||||
|     code.push(source_register); | ||||
| } | ||||
| 
 | ||||
| pub fn add_alloc(code: &mut Vec<u8>, register: u8, size: u32) { | ||||
| pub fn add_alloc(code: &mut Vec<u8>, register: u8, size: u32, implementation_name: &str) { | ||||
|     code.push(ALLOC); | ||||
|     code.push(register); | ||||
|     push_number!(code, size); | ||||
|     push_number!(code, implementation_name.len() as u32); | ||||
|     push_string!(code, implementation_name); | ||||
| } | ||||
| 
 | ||||
| pub fn add_alloc_raw(code: &mut Vec<u8>, 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<u8>, target_register: u8, source_register: u8) { | ||||
|     code.push(ALLOC_RAW_FROM); | ||||
|     code.push(target_register); | ||||
|     push_number!(code, source_register); | ||||
| } | ||||
| 
 | ||||
| pub fn add_dealloc(code: &mut Vec<u8>, register: u8) { | ||||
| @ -81,7 +111,33 @@ pub fn add_mov_int_to(code: &mut Vec<u8>, register: u8, offset: u32, operand: u3 | ||||
|     push_number!(code, operand); | ||||
| } | ||||
| 
 | ||||
| pub fn add_platform_call_to(code: &mut Vec<u8>, symbol_name: &String, return_register: u8, arg_registers_length: u8, arg_registers: &Vec<u8>) { | ||||
| pub fn add_mov_register_to( | ||||
|     code: &mut Vec<u8>, | ||||
|     target_register: u8, | ||||
|     offset: u32, | ||||
|     source_register: u8, | ||||
| ) { | ||||
|     code.push(MOV_REGISTER_TO); | ||||
|     code.push(target_register); | ||||
|     push_number!(code, offset); | ||||
|     code.push(source_register); | ||||
| } | ||||
| 
 | ||||
| pub fn add_mov_const(code: &mut Vec<u8>, register: u8, lib_name: &str, const_id: u32) { | ||||
|     code.push(MOV_CONST); | ||||
|     code.push(register); | ||||
|     push_number!(code, lib_name.len() as u32); | ||||
|     push_string!(code, lib_name); | ||||
|     push_number!(code, const_id); | ||||
| } | ||||
| 
 | ||||
| pub fn add_platform_call( | ||||
|     code: &mut Vec<u8>, | ||||
|     symbol_name: &str, | ||||
|     return_register: u8, | ||||
|     arg_registers_length: u8, | ||||
|     arg_registers: &Vec<u8>, | ||||
| ) { | ||||
|     code.push(PLATFORM_CALL); | ||||
|     push_number!(code, symbol_name.len() as u32); | ||||
|     push_string!(code, symbol_name); | ||||
| @ -91,3 +147,51 @@ pub fn add_platform_call_to(code: &mut Vec<u8>, symbol_name: &String, return_reg | ||||
|         code.push(b); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn add_invoke_fn(code: &mut Vec<u8>, fn_name: &str, return_register: u8, arg_registers: &[u8]) { | ||||
|     code.push(INVOKE_FN); | ||||
|     push_number!(code, fn_name.len() as u32); | ||||
|     push_string!(code, fn_name); | ||||
|     push_number!(code, return_register); | ||||
|     push_number!(code, arg_registers.len() as u8); | ||||
|     for &b in arg_registers { | ||||
|         code.push(b); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn add_invoke_method(code: &mut Vec<u8>, name: &str, arg_registers: &[u8]) { | ||||
|     code.push(INVOKE_METHOD); | ||||
|     push_number!(code, name.len() as u32); | ||||
|     push_string!(code, name); | ||||
|     push_number!(code, arg_registers.len() as u8); | ||||
|     for &b in arg_registers { | ||||
|         code.push(b); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn add_ret(code: &mut Vec<u8>) { | ||||
|     code.push(RETURN); | ||||
| } | ||||
| 
 | ||||
| pub fn add_ret_register(code: &mut Vec<u8>, register: u8) { | ||||
|     code.push(RETURN_REGISTER); | ||||
|     code.push(register); | ||||
| } | ||||
| 
 | ||||
| pub fn add_mov_size_of(code: &mut Vec<u8>, target_register: u8, source_register: u8) { | ||||
|     code.push(MOV_SIZE_OF); | ||||
|     code.push(target_register); | ||||
|     code.push(source_register); | ||||
| } | ||||
| 
 | ||||
| pub fn add_multiply( | ||||
|     code: &mut Vec<u8>, | ||||
|     target_register: u8, | ||||
|     left_register: u8, | ||||
|     right_register: u8, | ||||
| ) { | ||||
|     code.push(MULTIPLY); | ||||
|     code.push(target_register); | ||||
|     code.push(left_register); | ||||
|     code.push(right_register); | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| use crate::vm::dvm_value::DvmValue; | ||||
| use crate::vm::mem::DmAllocObject; | ||||
| use crate::vm::mem::{get_field_value, DmAllocObject}; | ||||
| use crate::vm::DmVirtualMachine; | ||||
| use std::rc::Rc; | ||||
| 
 | ||||
| @ -7,7 +7,9 @@ pub fn dm_print(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue { | ||||
|     if args.len() != 1 { | ||||
|         return DvmValue::Unit; // TODO: make exception
 | ||||
|     } | ||||
|     print!("{}", get_string(&args[0], vm)); | ||||
|     unsafe { | ||||
|         print!("{}", get_string(&args[0], vm)); | ||||
|     } | ||||
|     DvmValue::Unit | ||||
| } | ||||
| 
 | ||||
| @ -15,11 +17,13 @@ pub fn dm_println(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue { | ||||
|     if args.len() != 1 { | ||||
|         return DvmValue::Unit; | ||||
|     } | ||||
|     println!("{}", get_string(&args[0], vm)); | ||||
|     unsafe { | ||||
|         println!("{}", get_string(&args[0], vm)); | ||||
|     } | ||||
|     DvmValue::Unit | ||||
| } | ||||
| 
 | ||||
| fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String { | ||||
| unsafe fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String { | ||||
|     match dvm_value { | ||||
|         DvmValue::Byte(b) => b.to_string(), | ||||
|         DvmValue::Int(i) => i.to_string(), | ||||
| @ -27,24 +31,66 @@ fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> 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::ByteArray(_) => todo!(), | ||||
|         DvmValue::IntArray(_) => todo!(), | ||||
|         DvmValue::LongArray(_) => todo!(), | ||||
|         DvmValue::DoubleArray(_) => todo!(), | ||||
|         DvmValue::BooleanArray(_) => todo!(), | ||||
|         DvmValue::PointerArray(_) => todo!(), | ||||
|         DvmValue::Unit => String::from("Unit"), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn convert_to_string(alloc_object_rc: Rc<DmAllocObject>, vm: &mut DmVirtualMachine) -> String { | ||||
|     let to_string_result = vm.call_by_fqn( | ||||
|         "std::Display::to_string", | ||||
|         vec![DvmValue::Pointer(alloc_object_rc)], | ||||
|     ); | ||||
|     if let DvmValue::Pointer(to_string_result_alloc_object) = to_string_result { | ||||
|         todo!("Convert to_string_result_alloc_object (a String) to bytes to pass to print") | ||||
| unsafe fn convert_to_string( | ||||
|     alloc_object_rc: Rc<DmAllocObject>, | ||||
|     vm: &mut DmVirtualMachine, | ||||
| ) -> 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<u8> = 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), | ||||
|         } | ||||
|     } else { | ||||
|         panic!("to_string did not return a pointer") | ||||
|         todo!("what happens if we don't have a String?") | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user