Compare commits
	
		
			2 Commits
		
	
	
		
			d4280f40e1
			...
			6190beaed2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6190beaed2 | ||
|   | 97376bad72 | 
| @ -1,5 +1,8 @@ | |||||||
| ns std::core | ns std::core | ||||||
| 
 | 
 | ||||||
|  | use std::unsafe::Pointer | ||||||
|  | use std::unsafe::mem::{alloc, pointer_of) | ||||||
|  | 
 | ||||||
| pub int Array<T> : Monad + Default + Empty { | pub int Array<T> : Monad + Default + Empty { | ||||||
|     const default = array::empty<Self> |     const default = array::empty<Self> | ||||||
|     const empty = array::empty<Self> |     const empty = array::empty<Self> | ||||||
| @ -7,12 +10,42 @@ pub int Array<T> : Monad + Default + Empty { | |||||||
|     length: Int |     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 { | pub mod array { | ||||||
| 
 | 
 | ||||||
|     // Usage: |     // Usage: | ||||||
|     // let int_array = array::of(1, 2, 3) |     // let int_array = array::of(1, 2, 3) | ||||||
|     // assert_eq(3, int_array.length) |     // 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> |     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::DmVirtualMachine; | ||||||
| use deimos::vm::dvm_value::DvmValue; | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
|     // TODO:
 |     // Goal:
 | ||||||
|     // - write a single module with a main()
 |     // - write a single lib with a main()
 | ||||||
|     // - call the main fn
 |     // - call the main fn
 | ||||||
|     
 |     // fn main() { println "Hello, World!" }
 | ||||||
|     let mut code: Vec<u8> = Vec::new(); | 
 | ||||||
|     add_mov_int(&mut code, 0, 0x2a); // 42
 |     // std/unsafe/mem lib
 | ||||||
|     add_platform_call_to( |     let mut unsafe_mem_lib = DmLib::new("std/unsafe/mem"); | ||||||
|         &mut code, | 
 | ||||||
|         &String::from("std::core::println"), |     // std::unsafe::Pointer
 | ||||||
|         0, |     let unsafe_pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer"); | ||||||
|         1, |     let unsafe_pointer_rc = Rc::new(unsafe_pointer_int); | ||||||
|         &vec![0u8], | 
 | ||||||
|  |     // 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); |     let raw_address_field = DmField::new("raw_address", DmType::Long, 0); | ||||||
|     vm.call_by_fqn("default::main", vec![DvmValue::Unit; 0]); // will throw
 |     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 lexer; | ||||||
| pub mod parser; | pub mod parser; | ||||||
|  | mod util; | ||||||
| pub mod vm; | 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)] | #[derive(Debug, PartialEq, Eq)] | ||||||
| pub enum DmType { | pub enum DmType { | ||||||
|     Primitive(DmPrimitiveType), |  | ||||||
|     Object(Rc<DmObjectType>), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[derive(Debug, PartialEq, Eq)] |  | ||||||
| pub enum DmPrimitiveType { |  | ||||||
|     Byte, |     Byte, | ||||||
|     Int, |     Int, | ||||||
|     Long, |     Long, | ||||||
|     Double, |     Double, | ||||||
|     Boolean, |     Boolean, | ||||||
|     Pointer(Rc<DmType>), |     Pointer, | ||||||
|     ByteArray(usize), |  | ||||||
|     IntArray(usize), |  | ||||||
|     LongArray(usize), |  | ||||||
|     DoubleArray(usize), |  | ||||||
|     BooleanArray(usize), |  | ||||||
|     PointerArray(usize, Rc<DmType>), |  | ||||||
|     Unit, |     Unit, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl DmPrimitiveType { | impl DmType { | ||||||
|     pub fn size_in_bytes(&self) -> usize { |     pub fn size_in_bytes(&self) -> usize { | ||||||
|         match self { |         match self { | ||||||
|             DmPrimitiveType::Byte => size_of::<u8>(), |             DmType::Byte => size_of::<u8>(), | ||||||
|             DmPrimitiveType::Int => size_of::<i32>(), |             DmType::Int => size_of::<i32>(), | ||||||
|             DmPrimitiveType::Long => size_of::<i64>(), |             DmType::Long => size_of::<i64>(), | ||||||
|             DmPrimitiveType::Double => size_of::<f64>(), |             DmType::Double => size_of::<f64>(), | ||||||
|             DmPrimitiveType::Boolean => size_of::<bool>(), |             DmType::Boolean => size_of::<bool>(), | ||||||
|             DmPrimitiveType::Pointer(_) => size_of::<usize>(), |             DmType::Pointer => size_of::<usize>(), | ||||||
|             DmPrimitiveType::ByteArray(length) => *length * size_of::<u8>(), |             DmType::Unit => todo!("Need to determine size of Unit... is it dependent on the size of the thing which is Unit?") | ||||||
|             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?") |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| use std::rc::Rc; |  | ||||||
| use crate::vm::mem::DmAllocObject; | use crate::vm::mem::DmAllocObject; | ||||||
|  | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone, PartialEq)] | #[derive(Debug, Clone, PartialEq)] | ||||||
| pub enum DvmValue { | pub enum DvmValue { | ||||||
| @ -9,11 +9,5 @@ pub enum DvmValue { | |||||||
|     Double(f64), |     Double(f64), | ||||||
|     Boolean(bool), |     Boolean(bool), | ||||||
|     Pointer(Rc<DmAllocObject>), |     Pointer(Rc<DmAllocObject>), | ||||||
|     ByteArray(Vec<u8>), |  | ||||||
|     IntArray(Vec<i32>), |  | ||||||
|     LongArray(Vec<i64>), |  | ||||||
|     DoubleArray(Vec<f64>), |  | ||||||
|     BooleanArray(Vec<bool>), |  | ||||||
|     PointerArray(Vec<Rc<DmAllocObject>>), |  | ||||||
|     Unit, |     Unit, | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,89 +1,13 @@ | |||||||
| use std::rc::Rc; |  | ||||||
| use crate::get_32_le; | 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 fn load_module(bytes: &[u8]) -> Result<DmLib, String> { | ||||||
| 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> { |  | ||||||
|     let mut ip: usize = 0; |     let mut ip: usize = 0; | ||||||
|     // Check for magic number at bytes 0..5
 |     // Check for magic number at bytes 0..5
 | ||||||
|     if !check_deimos(&bytes) { |     if !check_deimos(&bytes) { | ||||||
|         return Err(String::from("Not a valid Deimos module.")); |         return Err(String::from("Not a valid Deimos lib.")); | ||||||
|     } |     } | ||||||
|     ip = 6; |     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
 |     // Check version string. We'll use this in the future to not load modules compiled later than
 | ||||||
|     // current version.
 |     // current version.
 | ||||||
|     if version_string != "0.1.0" { |     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
 |     // 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
 |     // 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); |     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,
 |     // For each "row" in the symbol table,
 | ||||||
|     // 1. Get the type
 |     // 1. Get the type
 | ||||||
|     // 2. Obtain the name's length and then get the name in utf8
 |     // 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 { |     while ip < symbol_table_end { | ||||||
|         let type_byte = bytes[ip]; |         let type_byte = bytes[ip]; | ||||||
|         ip += 1; |         ip += 1; | ||||||
| @ -129,16 +53,12 @@ pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> { | |||||||
|         ip += name_string_length; |         ip += name_string_length; | ||||||
|         let address = get_32_le!(bytes, ip, 0, u32); |         let address = get_32_le!(bytes, ip, 0, u32); | ||||||
|         ip += 4; |         ip += 4; | ||||||
|         let symbol_type = match type_byte { |         let lib_symbol = match type_byte { | ||||||
|             CONST_SYMBOL => SymbolType::Constant, |             CONST_SYMBOL => LibSymbol::Constant(name, address), | ||||||
|             FUNCTION_SYMBOL => SymbolType::Function, |             FUNCTION_SYMBOL => LibSymbol::Function(name, address), | ||||||
|             _ => return Err(String::from("Invalid Deimos symbol type.")), |             _ => return Err(String::from("Invalid Deimos symbol type.")), | ||||||
|         }; |         }; | ||||||
|         symbols.push(DmSymbol { |         symbols.push(lib_symbol); | ||||||
|             name, |  | ||||||
|             address, |  | ||||||
|             symbol_type, |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     todo!() |     todo!() | ||||||
| @ -163,7 +83,7 @@ fn read_as_u64(bytes: &[u8]) -> u64 { | |||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod read_as_u64_tests { | mod read_as_u64_tests { | ||||||
|     use crate::vm::module::{read_as_u64, DEIMOS_MAGIC_NUMBER}; |     use super::*; | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn read_6_bytes() { |     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::dvm_value::DvmValue; | ||||||
| use crate::vm::object_type::DmImplementation; | use crate::vm::object_type::{DmField, DmImplementation}; | ||||||
| use crate::vm::object_type::DmProperty; |  | ||||||
| use std::alloc::Layout; | use std::alloc::Layout; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| @ -13,48 +12,30 @@ pub struct DmAllocObject { | |||||||
|     pub implementation: Rc<DmImplementation>, |     pub implementation: Rc<DmImplementation>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub unsafe fn get_property_value( | pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -> DvmValue { | ||||||
|     dm_property: &DmProperty, |     let data_size = dm_field.dm_type().size_in_bytes(); | ||||||
|     self_object: &DmAllocObject, |  | ||||||
| ) -> DvmValue { |  | ||||||
|     let data_size = dm_property.primitive_type.size_in_bytes(); |  | ||||||
|     let mut raw_data: Vec<u8> = Vec::with_capacity(data_size); |     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()); |         raw_data.push(self_object.data.offset(i as isize).read()); | ||||||
|     } |     } | ||||||
|     match dm_property.primitive_type.as_ref() { |     match dm_field.dm_type() { | ||||||
|         DmPrimitiveType::Byte => DvmValue::Byte(raw_data[0]), |         DmType::Byte => DvmValue::Byte(raw_data[0]), | ||||||
|         DmPrimitiveType::Int => DvmValue::Int(i32::from_ne_bytes( |         DmType::Int => DvmValue::Int(i32::from_ne_bytes( | ||||||
|             raw_data[0..data_size].try_into().unwrap(), |             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(), |             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(), |             raw_data[0..data_size].try_into().unwrap(), | ||||||
|         )), |         )), | ||||||
|         DmPrimitiveType::Boolean => DvmValue::Boolean(raw_data[0] == 1), |         DmType::Boolean => DvmValue::Boolean(raw_data[0] == 1), | ||||||
|         DmPrimitiveType::Pointer(_) => { |         DmType::Pointer => { | ||||||
|             // read the pointer's (address) value
 |             // read the pointer's (address) value
 | ||||||
|             let address = usize::from_ne_bytes(raw_data[0..data_size].try_into().unwrap()); |             let address = usize::from_ne_bytes(raw_data[0..data_size].try_into().unwrap()); | ||||||
|             DvmValue::Pointer(Rc::from_raw(address as *const DmAllocObject)) |             DvmValue::Pointer(Rc::from_raw(address as *const DmAllocObject)) | ||||||
|         } |         } | ||||||
|         DmPrimitiveType::ByteArray(_) => DvmValue::ByteArray(raw_data), |         DmType::Unit => DvmValue::Unit, | ||||||
|         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, |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										226
									
								
								src/vm/mod.rs
									
									
									
									
									
								
							
							
						
						
									
										226
									
								
								src/vm/mod.rs
									
									
									
									
									
								
							| @ -1,17 +1,19 @@ | |||||||
| pub mod dm_type; | pub mod dm_type; | ||||||
| pub mod dvm_value; | pub mod dvm_value; | ||||||
| mod mem; | pub mod lib; | ||||||
| pub mod module; | pub mod mem; | ||||||
| mod object_type; | pub mod object_type; | ||||||
| pub mod op_codes; | pub mod op_codes; | ||||||
| pub mod platform; | pub mod platform; | ||||||
| pub mod util; | pub mod util; | ||||||
| 
 | 
 | ||||||
| use crate::vm::dvm_value::DvmValue; | 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::object_type::DmFn; | ||||||
| use crate::vm::platform::init_platform_functions; | use crate::vm::platform::init_platform_functions; | ||||||
| use op_codes::*; | use op_codes::*; | ||||||
|  | use std::alloc::{alloc, Layout}; | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| use util::{get_32_le, get_64_le}; | use util::{get_32_le, get_64_le}; | ||||||
| @ -33,7 +35,7 @@ struct DeimosCallFrame { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct DmVirtualMachine { | pub struct DmVirtualMachine { | ||||||
|     modules: Vec<DmModule>, |     libs: Vec<DmLib>, | ||||||
|     functions: HashMap<String, Rc<DmFn>>, |     functions: HashMap<String, Rc<DmFn>>, | ||||||
|     platform_functions: HashMap<String, PlatformFunction>, |     platform_functions: HashMap<String, PlatformFunction>, | ||||||
|     ip: usize, |     ip: usize, | ||||||
| @ -42,35 +44,51 @@ pub struct DmVirtualMachine { | |||||||
|     register_state_stack: Vec<Vec<DvmValue>>, |     register_state_stack: Vec<Vec<DvmValue>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn load_functions(modules: &Vec<DmModule>) -> HashMap<String, Rc<DmFn>> { | fn load_functions(destination: &mut HashMap<String, Rc<DmFn>>, libs: &Vec<DmLib>) { | ||||||
|     let mut functions: HashMap<String, Rc<DmFn>> = HashMap::new(); |     for module in libs { | ||||||
|     for module in modules { |         for lib_fn in &module.functions { | ||||||
|         for module_fn in &module.functions { |             destination.insert(lib_fn.fqn.clone(), lib_fn.clone()); | ||||||
|             functions.insert(module_fn.fqn.clone(), module_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 { | impl DmVirtualMachine { | ||||||
|     pub fn new(modules: Vec<DmModule>) -> DmVirtualMachine { |     pub fn new(libs: Vec<DmLib>) -> DmVirtualMachine { | ||||||
|         DmVirtualMachine { |         let mut vm = DmVirtualMachine { | ||||||
|             modules, |             libs: libs, | ||||||
|             functions: HashMap::new(), |             functions: HashMap::new(), | ||||||
|             platform_functions: init_platform_functions(), |             platform_functions: init_platform_functions(), | ||||||
|             ip: 0, |             ip: 0, | ||||||
|             registers: Vec::new(), |             registers: Vec::new(), | ||||||
|             call_stack: Vec::new(), |             call_stack: Vec::new(), | ||||||
|             register_state_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 { |     pub fn get_fn_by_fqn(&self, fqn: &str) -> Option<Rc<DmFn>> { | ||||||
|         todo!() |         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
 |         // save current state
 | ||||||
|         self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame { |         self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame { | ||||||
|             return_address: self.ip, |             return_address: self.ip, | ||||||
| @ -79,7 +97,9 @@ impl DmVirtualMachine { | |||||||
| 
 | 
 | ||||||
|         // zero registers and make sure there are enough for dm_function
 |         // zero registers and make sure there are enough for dm_function
 | ||||||
|         self.registers.clear(); |         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
 |         // push args
 | ||||||
|         for i in 0..args.len() { |         for i in 0..args.len() { | ||||||
| @ -96,12 +116,14 @@ impl DmVirtualMachine { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // return result
 |         // 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>) { |     pub fn run_raw(&mut self, code: &Vec<u8>) { | ||||||
|         let mut i = 0; |         let mut i = 0; | ||||||
|         while i < code.len() { |         while i < code.len() { | ||||||
|  |             let op_code = code[i]; | ||||||
|  |             println!("op_code: {:#04x}", op_code); | ||||||
|             match code[i] { |             match code[i] { | ||||||
|                 MOV_INT => { |                 MOV_INT => { | ||||||
|                     let target_register = code[i + 1] as usize; |                     let target_register = code[i + 1] as usize; | ||||||
| @ -117,7 +139,9 @@ impl DmVirtualMachine { | |||||||
|                         .insert(target_register, DvmValue::Long(operand as i64)); |                         .insert(target_register, DvmValue::Long(operand as i64)); | ||||||
|                     i += 10; |                     i += 10; | ||||||
|                 } |                 } | ||||||
|                 MOV_DOUBLE => { /* todo */ } |                 MOV_DOUBLE => { | ||||||
|  |                     unimplemented!(); | ||||||
|  |                 } | ||||||
|                 MOV_REGISTER => { |                 MOV_REGISTER => { | ||||||
|                     let target_register = code[i + 1] as usize; |                     let target_register = code[i + 1] as usize; | ||||||
|                     let source_register = code[i + 2] as usize; |                     let source_register = code[i + 2] as usize; | ||||||
| @ -126,7 +150,46 @@ impl DmVirtualMachine { | |||||||
|                     i += 3; |                     i += 3; | ||||||
|                 } |                 } | ||||||
|                 ALLOC => { |                 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 => { |                 DEALLOC => { | ||||||
|                     todo!() |                     todo!() | ||||||
| @ -134,6 +197,79 @@ impl DmVirtualMachine { | |||||||
|                 MOV_INT_TO => { |                 MOV_INT_TO => { | ||||||
|                     todo!() |                     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 => { |                 PLATFORM_CALL => { | ||||||
|                     i += 1; |                     i += 1; | ||||||
| 
 | 
 | ||||||
| @ -169,7 +305,47 @@ impl DmVirtualMachine { | |||||||
|                     let call_result = platform_function(args, self); |                     let call_result = platform_function(args, self); | ||||||
|                     self.registers.insert(return_register, call_result); |                     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] |     #[test] | ||||||
|  |     #[ignore] | ||||||
|     fn mov_int_to_register_as_address() { |     fn mov_int_to_register_as_address() { | ||||||
|         let mut code = Vec::new(); |         let mut code = Vec::new(); | ||||||
|         add_alloc(&mut code, 0, 4); |         add_alloc(&mut code, 0, 4); | ||||||
| @ -240,6 +417,7 @@ mod dvm_run_tests { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|  |     #[ignore] | ||||||
|     fn alloc_and_dealloc_expect_register_cleared() { |     fn alloc_and_dealloc_expect_register_cleared() { | ||||||
|         let mut code = Vec::new(); |         let mut code = Vec::new(); | ||||||
|         add_alloc(&mut code, 0, 4); |         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 crate::vm::mem::DmAllocObject; | ||||||
| use std::fmt::Debug; | use std::fmt::Debug; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| @ -13,9 +13,35 @@ pub enum DmObjectType { | |||||||
| pub struct DmFn { | pub struct DmFn { | ||||||
|     pub fqn: String, |     pub fqn: String, | ||||||
|     pub short_name: String, |     pub short_name: String, | ||||||
|     pub implements: Option<DmVirtualMethod>, |  | ||||||
|     pub byte_code: Vec<u8>, |     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 { | 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)] | #[derive(Debug, Eq)] | ||||||
| pub struct DmInterface { | pub struct DmInterface { | ||||||
|     pub fqn: String, |     fqn: String, | ||||||
|     short_name: String, |     short_name: String, | ||||||
|     properties: Vec<Rc<DmProperty>>, |     functions: Vec<Rc<DmFn>>, | ||||||
|     virtual_methods: Vec<Rc<DmVirtualMethod>>, |     virtual_methods: Vec<Rc<DmVirtualMethod>>, | ||||||
|     impl_methods: Vec<Rc<DmFn>>, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PartialEq for DmInterface { | impl PartialEq for DmInterface { | ||||||
| @ -40,10 +86,37 @@ impl PartialEq for DmInterface { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl DmInterface { | impl DmInterface { | ||||||
|     pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmFn>> { |     pub fn new(fqn: &str, short_name: &str) -> Self { | ||||||
|         if let Some(dm_fn) = self.impl_methods.iter().find(|&dm_fn| dm_fn.fqn == name) { |         DmInterface { | ||||||
|             return Some(dm_fn.clone()); |             fqn: fqn.to_string(), | ||||||
|         } else if self |             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 |             .virtual_methods | ||||||
|             .iter() |             .iter() | ||||||
|             .find(|&dm_fn| dm_fn.fqn == name) |             .find(|&dm_fn| dm_fn.fqn == name) | ||||||
| @ -53,6 +126,10 @@ impl DmInterface { | |||||||
|         } |         } | ||||||
|         None |         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> { |     pub fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmProperty> { | ||||||
|         todo!() |         todo!() | ||||||
| @ -75,11 +152,10 @@ impl PartialEq for DmVirtualMethod { | |||||||
| pub struct DmImplementation { | pub struct DmImplementation { | ||||||
|     pub fqn: String, |     pub fqn: String, | ||||||
|     pub short_name: String, |     pub short_name: String, | ||||||
|     pub interface: Rc<DmInterface>, |     pub interface: Option<Rc<DmInterface>>, | ||||||
|     pub size_in_bytes: usize, |     pub functions: Vec<Rc<DmFn>>, | ||||||
|     properties: Vec<DmProperty>, |     pub methods: Vec<Rc<DmMethod>>, | ||||||
|     fields: Vec<DmField>, |     pub fields: Vec<DmField>, | ||||||
|     methods: Vec<Rc<DmFn>>, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PartialEq for DmImplementation { | impl PartialEq for DmImplementation { | ||||||
| @ -89,9 +165,24 @@ impl PartialEq for DmImplementation { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl 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 { |         for method in &self.methods { | ||||||
|             if method.fqn == name { |             if method.dm_fn.fqn == name { | ||||||
|                 return Some(method.clone()); |                 return Some(method.clone()); | ||||||
|             } else if let Some(implements) = &method.implements { |             } else if let Some(implements) = &method.implements { | ||||||
|                 if implements.fqn == name { |                 if implements.fqn == name { | ||||||
| @ -106,8 +197,12 @@ impl DmImplementation { | |||||||
|         todo!() |         todo!() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmField>> { |     pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmField> { | ||||||
|         todo!() |         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 struct DmProperty { | ||||||
|     pub name: String, |     pub name: String, | ||||||
|     pub data_offset: usize, |     pub data_offset: usize, | ||||||
|     pub primitive_type: Rc<DmPrimitiveType>, |     pub primitive_type: Rc<DmType>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PartialEq for DmProperty { | impl PartialEq for DmProperty { | ||||||
| @ -127,7 +222,8 @@ impl PartialEq for DmProperty { | |||||||
| #[derive(Debug, Eq)] | #[derive(Debug, Eq)] | ||||||
| pub struct DmField { | pub struct DmField { | ||||||
|     name: String, |     name: String, | ||||||
|     primitive_type: Rc<DmPrimitiveType>, |     dm_type: DmType, | ||||||
|  |     data_offset: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PartialEq for DmField { | impl PartialEq for DmField { | ||||||
| @ -135,3 +231,29 @@ impl PartialEq for DmField { | |||||||
|         self.name == other.name |         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_DOUBLE_TO: u8 = 0x09; | ||||||
| pub const MOV_REGISTER_TO: u8 = 0x0a; | 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 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 { | macro_rules! push_number { | ||||||
|     ( $dest: expr, $num: expr ) => { |     ( $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); |     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(ALLOC); | ||||||
|     code.push(register); |     code.push(register); | ||||||
|     push_number!(code, size); |     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) { | 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); |     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); |     code.push(PLATFORM_CALL); | ||||||
|     push_number!(code, symbol_name.len() as u32); |     push_number!(code, symbol_name.len() as u32); | ||||||
|     push_string!(code, symbol_name); |     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); |         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::dvm_value::DvmValue; | ||||||
| use crate::vm::mem::DmAllocObject; | use crate::vm::mem::{get_field_value, DmAllocObject}; | ||||||
| use crate::vm::DmVirtualMachine; | use crate::vm::DmVirtualMachine; | ||||||
| use std::rc::Rc; | use std::rc::Rc; | ||||||
| 
 | 
 | ||||||
| @ -7,7 +7,9 @@ pub fn dm_print(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue { | |||||||
|     if args.len() != 1 { |     if args.len() != 1 { | ||||||
|         return DvmValue::Unit; // TODO: make exception
 |         return DvmValue::Unit; // TODO: make exception
 | ||||||
|     } |     } | ||||||
|     print!("{}", get_string(&args[0], vm)); |     unsafe { | ||||||
|  |         print!("{}", get_string(&args[0], vm)); | ||||||
|  |     } | ||||||
|     DvmValue::Unit |     DvmValue::Unit | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -15,11 +17,13 @@ pub fn dm_println(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue { | |||||||
|     if args.len() != 1 { |     if args.len() != 1 { | ||||||
|         return DvmValue::Unit; |         return DvmValue::Unit; | ||||||
|     } |     } | ||||||
|     println!("{}", get_string(&args[0], vm)); |     unsafe { | ||||||
|  |         println!("{}", get_string(&args[0], vm)); | ||||||
|  |     } | ||||||
|     DvmValue::Unit |     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 { |     match dvm_value { | ||||||
|         DvmValue::Byte(b) => b.to_string(), |         DvmValue::Byte(b) => b.to_string(), | ||||||
|         DvmValue::Int(i) => i.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::Double(d) => d.to_string(), | ||||||
|         DvmValue::Boolean(b) => b.to_string(), |         DvmValue::Boolean(b) => b.to_string(), | ||||||
|         DvmValue::Pointer(alloc_object_rc) => convert_to_string(alloc_object_rc.clone(), vm), |         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"), |         DvmValue::Unit => String::from("Unit"), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn convert_to_string(alloc_object_rc: Rc<DmAllocObject>, vm: &mut DmVirtualMachine) -> String { | unsafe fn convert_to_string( | ||||||
|     let to_string_result = vm.call_by_fqn( |     alloc_object_rc: Rc<DmAllocObject>, | ||||||
|         "std::Display::to_string", |     vm: &mut DmVirtualMachine, | ||||||
|         vec![DvmValue::Pointer(alloc_object_rc)], | ) -> String { | ||||||
|     ); |     if alloc_object_rc.implementation.fqn == "std::core::String" { | ||||||
|     if let DvmValue::Pointer(to_string_result_alloc_object) = to_string_result { |         let bytes_field = alloc_object_rc | ||||||
|         todo!("Convert to_string_result_alloc_object (a String) to bytes to pass to print") |             .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 { |     } 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