Compare commits

..

No commits in common. "21250ea69539995eb6c71bc8701c3ec629e2aad1" and "6190beaed268fc65b4db3c52c09542c62f77fe52" have entirely different histories.

11 changed files with 561 additions and 756 deletions

View File

@ -12,7 +12,7 @@ pub int Array<T> : Monad + Default + Empty {
impl ArrayImpl<T> : Array<T> { impl ArrayImpl<T> : Array<T> {
fld pointer: Pointer fld pointer: Pointer<T>
fld length: Int fld length: Int
pub unsafe ctor(length: Int) { pub unsafe ctor(length: Int) {
@ -20,12 +20,12 @@ impl ArrayImpl<T> : Array<T> {
self.length = length self.length = length
} }
pub ctor(pointer: Pointer, length: Int) { pub ctor(pointer: Pointer<T>, length: Int) {
self.pointer = pointer self.pointer = pointer
self.length = length self.length = length
} }
pub unsafe fn set(index: Int, item: Pointer) { pub unsafe fn set(index: Int, item: Pointer<T>) {
pointer.offset(index * T::size()).write(item.read()) pointer.offset(index * T::size()).write(item.read())
} }

View File

@ -13,7 +13,8 @@ pub int String : Display {
} }
impl StringImpl(bytes: Array<Byte>, /* encoding: Encoding */) { impl Utf8String(bytes: Array<Byte>) : String {
encoding = Encoding::Utf8
length = bytes.length length = bytes.length
characters = lazy { characters = lazy {
todo('parse the utf8 bytes and return an Array<Character>') todo('parse the utf8 bytes and return an Array<Character>')
@ -26,6 +27,6 @@ pub mod string {
// let bytes = array::of(0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73) // let bytes = array::of(0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73)
// let s = string::from_utf8_bytes(bytes) // let s = string::from_utf8_bytes(bytes)
// println s // "deimos" // println s // "deimos"
fn from_utf8_bytes(bytes: Array<Byte>): String = StringImpl(bytes, /* Encoding::Utf8 */) fn from_utf8_bytes(bytes: Array<Byte>): String = Utf8String(bytes)
} }

View File

@ -1,14 +1,18 @@
ns std::unsafe ns std::unsafe
pub int Pointer pub int Pointer<T> {}
// Contains two fields: impl PointerImpl<T> {
// fld raw_address: Long
// fld size: Long fld raw_address: Long
decl impl PointerImpl(size: Long) : Pointer fld size: Long
decl ctor(size: Long)
}
pub mod mem { pub mod mem {
pub fn alloc(size: Long): Pointer = PointerImpl(size) pub fn <T> alloc(size: Long): Pointer<T> = PointerImpl(size)
} }

View File

@ -2,10 +2,11 @@ use deimos::vm::dm_type::DmType;
use deimos::vm::lib::{DmConstant, DmLib}; use deimos::vm::lib::{DmConstant, DmLib};
use deimos::vm::object_type::{DmField, DmFn, DmImplementation, DmInterface, DmMethod}; use deimos::vm::object_type::{DmField, DmFn, DmImplementation, DmInterface, DmMethod};
use deimos::vm::op_codes::{ use deimos::vm::op_codes::{
add_alloc, add_alloc_raw_from, add_invoke_fn, add_mov_const, add_mov_register_to, add_alloc, add_alloc_raw_from, add_invoke_fn, add_invoke_method, add_mov_const,
add_mov_size_of, add_multiply, add_platform_call, add_mov_register_to, add_mov_size_of, add_multiply, add_platform_call, add_ret,
add_ret_register,
}; };
use deimos::vm::{call_fn, DvmContext, DvmState}; use deimos::vm::DmVirtualMachine;
use std::rc::Rc; use std::rc::Rc;
fn main() { fn main() {
@ -15,62 +16,61 @@ fn main() {
// fn main() { println "Hello, World!" } // fn main() { println "Hello, World!" }
// std/unsafe/mem lib // std/unsafe/mem lib
let mut mem_lib = DmLib::new("std/unsafe/mem"); let mut unsafe_mem_lib = DmLib::new("std/unsafe/mem");
// std::unsafe::Pointer // std::unsafe::Pointer
let pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer"); let unsafe_pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer");
let pointer_int_rc = Rc::new(pointer_int); let unsafe_pointer_rc = Rc::new(unsafe_pointer_int);
// std::unsafe::PointerImpl : Pointer // std::unsafe::PointerImpl : Pointer
let mut pointer_impl = DmImplementation::new( let mut unsafe_pointer_impl = DmImplementation::new(
"std::unsafe:PointerImpl", "std::unsafe:PointerImpl",
"PointerImpl", "PointerImpl",
Some(pointer_int_rc.clone()), Some(unsafe_pointer_rc.clone()),
); );
let pointer_impl_raw_address = DmField::new("raw_address", DmType::Long, 0); let raw_address_field = DmField::new("raw_address", DmType::Long, 0);
let pointer_impl_size = DmField::new("size", DmType::Long, 8); let size_field = DmField::new("size", DmType::Long, 8);
// std::unsafe::PointerImpl::_ctor_0( // std::unsafe::Pointer::_ctor_0(
// r0: self // r0: self
// r1: size Long // r1: size Long
// ) // )
// r2: raw_address Long // r2: raw_address Long
let mut pointer_impl_ctor_0_code: Vec<u8> = Vec::new(); let mut unsafe_pointer_ctor_0_bytecode: Vec<u8> = Vec::new();
add_alloc_raw_from(&mut pointer_impl_ctor_0_code, 2, 1); add_alloc_raw_from(&mut unsafe_pointer_ctor_0_bytecode, 2, 1);
add_mov_register_to( add_mov_register_to(
&mut pointer_impl_ctor_0_code, &mut unsafe_pointer_ctor_0_bytecode,
0, 0,
pointer_impl_raw_address.data_offset() as u32, raw_address_field.data_offset() as u32,
2, 2,
); );
add_mov_register_to( add_mov_register_to(
&mut pointer_impl_ctor_0_code, &mut unsafe_pointer_ctor_0_bytecode,
0, 0,
pointer_impl_size.data_offset() as u32, size_field.data_offset() as u32,
1, 1,
); );
let pointer_impl_ctor_0_fn = DmFn::new( let unsafe_pointer_init_fn = DmFn::new(
"std::unsafe::PointerImpl::_ctor_0", "std::unsafe::PointerImpl::_ctor_0",
"_ctor_0", "_ctor_0",
pointer_impl_ctor_0_code, unsafe_pointer_ctor_0_bytecode,
3, 3,
None,
); );
let pointer_impl_ctor_0_method = DmMethod::new(pointer_impl_ctor_0_fn, None); let unsafe_pointer_init_method = DmMethod::new(unsafe_pointer_init_fn, None);
pointer_impl.fields.push(pointer_impl_raw_address); unsafe_pointer_impl.fields.push(raw_address_field);
pointer_impl.fields.push(pointer_impl_size); unsafe_pointer_impl.fields.push(size_field);
pointer_impl unsafe_pointer_impl
.methods .methods
.push(Rc::new(pointer_impl_ctor_0_method)); .push(Rc::new(unsafe_pointer_init_method));
let unsafe_pointer_impl_rc = Rc::new(pointer_impl); let unsafe_pointer_impl_rc = Rc::new(unsafe_pointer_impl);
mem_lib.interfaces.push(pointer_int_rc.clone()); unsafe_mem_lib.interfaces.push(unsafe_pointer_rc.clone());
mem_lib unsafe_mem_lib
.implementations .implementations
.push(unsafe_pointer_impl_rc.clone()); .push(unsafe_pointer_impl_rc.clone());
@ -79,44 +79,39 @@ fn main() {
// ) // )
// r0: size Long // r0: size Long
// r1: Pointer object // r1: Pointer object
// r2: Void from PointerImpl::_ctor_0
// @return r1 // @return r1
let mut alloc_fn_code: Vec<u8> = Vec::new(); let mut alloc_fn_byte_code: Vec<u8> = Vec::new();
add_alloc( add_alloc(
&mut alloc_fn_code, &mut alloc_fn_byte_code,
1, 1,
unsafe_pointer_impl_rc.size_in_bytes() as u32, unsafe_pointer_impl_rc.size_in_bytes() as u32,
"std::unsafe::PointerImpl", "std::unsafe::PointerImpl",
); );
add_invoke_fn( add_invoke_method(
&mut alloc_fn_code, &mut alloc_fn_byte_code,
"std::unsafe::PointerImpl::_ctor_0", "std::unsafe::Pointer::_ctor_0",
2,
&[1u8, 0u8], &[1u8, 0u8],
); );
add_ret_register(&mut alloc_fn_byte_code, 1);
let alloc_fn = DmFn::new( let alloc_fn = DmFn {
"std::unsafe::mem::alloc", fqn: "std::unsafe::mem::alloc".to_string(),
"alloc", short_name: "alloc".to_string(),
alloc_fn_code, byte_code: alloc_fn_byte_code,
3, number_used_registers: 2,
Some(1), };
);
mem_lib.functions.push(Rc::new(alloc_fn)); unsafe_mem_lib.functions.push(Rc::new(alloc_fn));
// std/core/array lib
let mut array_lib = DmLib::new("std/core/array");
// std::core::Array // std::core::Array
let array_int = DmInterface::new("std::core::Array", "Array"); let core_array_int = DmInterface::new("std::core::Array", "Array");
let array_int_rc = Rc::new(array_int); let core_array_int_rc = Rc::new(core_array_int);
// std::core::ArrayImpl // std::core::ArrayImpl
let mut array_impl = DmImplementation::new( let mut core_array_impl = DmImplementation::new(
"std::core::ArrayImpl", "std::core::ArrayImpl",
"ArrayImpl", "ArrayImpl",
Some(array_int_rc.clone()), Some(core_array_int_rc.clone()),
); );
let array_impl_pointer_fld = DmField::new("pointer", DmType::Pointer, 0); let array_impl_pointer_fld = DmField::new("pointer", DmType::Pointer, 0);
@ -158,18 +153,16 @@ fn main() {
"_ctor_0", "_ctor_0",
array_impl_ctor_0_bytecode, array_impl_ctor_0_bytecode,
6, 6,
None,
); );
let array_impl_ctor_0_method = DmMethod::new(array_impl_ctor_0_fn, None); let array_impl_ctor_0_method = DmMethod::new(array_impl_ctor_0_fn, None);
array_impl.methods.push(Rc::new(array_impl_ctor_0_method)); core_array_impl
.methods
// Add Array and ArrayImpl to array lib .push(Rc::new(array_impl_ctor_0_method));
array_lib.interfaces.push(array_int_rc.clone());
array_lib.implementations.push(Rc::new(array_impl));
// std::core::String // std::core::String
let mut string_lib = DmLib::new("std/core/string");
let mut string_impl = DmImplementation::new("std::core::String", "String", None); 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); let bytes_field = DmField::new("bytes", DmType::Pointer, 0);
@ -177,31 +170,31 @@ fn main() {
// r0: self // r0: self
// r1: DvmPointer to Array<Byte> // r1: DvmPointer to Array<Byte>
// ) // )
let mut string_ctor_0_bytecode: Vec<u8> = Vec::new(); let mut core_string_ctor_0_bytecode: Vec<u8> = Vec::new();
add_mov_register_to( add_mov_register_to(
&mut string_ctor_0_bytecode, &mut core_string_ctor_0_bytecode,
0, 0,
bytes_field.data_offset() as u32, bytes_field.data_offset() as u32,
1, 1,
); );
let string_ctor_0_fn = DmFn::new( let core_string_ctor_0_fn = DmFn {
"std::core::String::_ctor_0", fqn: "std::core::String::_ctor_0".to_string(),
"_ctor_0", short_name: "_ctor_0".to_string(),
string_ctor_0_bytecode, byte_code: core_string_ctor_0_bytecode,
2, number_used_registers: 2,
None, };
);
let core_string_ctor_0_method = DmMethod::new(core_string_ctor_0_fn, None);
let string_ctor_0_method = DmMethod::new(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();
string_impl.fields.push(bytes_field); core_string_lib
string_impl.methods.push(Rc::new(string_ctor_0_method)); .implementations
let core_string_impl_size = string_impl.size_in_bytes(); .push(Rc::new(core_string_impl));
string_lib.implementations.push(Rc::new(string_impl));
// greeting lib
let mut greeting_lib = DmLib::new("greeting"); let mut greeting_lib = DmLib::new("greeting");
greeting_lib greeting_lib
.constants .constants
@ -209,9 +202,9 @@ fn main() {
let mut main_byte_code = Vec::new(); let mut main_byte_code = Vec::new();
// 1. Move constant: r0 receives DvmValue::Pointer to ArrayImpl<Byte> // 1. Move constant: r0 receives DvmValue::Pointer to Array<Byte>
// 2. Allocate for std::core::StringImpl into r1 // 2. Allocate for std::core::String into r1
// 3. Call StringImpl::_ctor_0(r0) -> r2 // 3. Call String::_ctor_0(r0) -> r2
// 4. Platform call std::core::println(r1) -> r3 // 4. Platform call std::core::println(r1) -> r3
add_alloc( add_alloc(
&mut main_byte_code, &mut main_byte_code,
@ -220,22 +213,21 @@ fn main() {
"std::core::String", "std::core::String",
); );
add_mov_const(&mut main_byte_code, 1, "greeting", 0); add_mov_const(&mut main_byte_code, 1, "greeting", 0);
add_invoke_fn( add_invoke_method(&mut main_byte_code, "std::core::String::_init_0", &[0, 1]);
&mut main_byte_code, add_platform_call(&mut main_byte_code, "std::core::println", 0, 1, &vec![0u8]);
"std::core::StringImpl::_ctor_0",
2,
&[0, 1],
);
add_platform_call(&mut main_byte_code, "std::core::println", 3, 1, &vec![0u8]);
let main_dm_fn = DmFn::new("main", "main", main_byte_code, 2, None); 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)); greeting_lib.functions.push(Rc::new(main_dm_fn));
let mut state = DvmState::new(); let mut vm = DmVirtualMachine::new(vec![greeting_lib, core_string_lib]);
let mut context = DvmContext::new(); let main_fn = vm
context.load_functions(&vec![greeting_lib, string_lib, mem_lib]); .get_fn_by_fqn("default::main")
.expect("Could not find function: default::main");
let main_fn = context.fn_by_fqn("main").unwrap(); vm.call_fn(&main_fn, Vec::new());
call_fn(&mut state, &context, &main_fn, vec![]);
} }

View File

@ -9,24 +9,5 @@ pub enum DvmValue {
Double(f64), Double(f64),
Boolean(bool), Boolean(bool),
Pointer(Rc<DmAllocObject>), Pointer(Rc<DmAllocObject>),
Uninit, Unit,
Void,
}
impl DvmValue {
pub fn expect_long(&self) -> i64 {
if let DvmValue::Long(l) = self {
*l
} else {
panic!("Expected DvmValue::long, but found {:?}", self)
}
}
pub fn expect_pointer(&self) -> Rc<DmAllocObject> {
if let DvmValue::Pointer(p) = self {
p.clone()
} else {
panic!("Expected DvmValue::Pointer, but found {:?}", self);
}
}
} }

View File

@ -26,7 +26,6 @@ impl DmLib {
} }
} }
#[derive(Debug)]
pub enum DmConstant { pub enum DmConstant {
String(String), String(String),
} }

View File

@ -1,40 +1,17 @@
use crate::vm::dm_type::DmType; use crate::vm::dm_type::DmType;
use crate::vm::dvm_value::DvmValue; use crate::vm::dvm_value::DvmValue;
use crate::vm::object_type::{DmField, DmImplementation}; use crate::vm::object_type::{DmField, DmImplementation};
use std::alloc::{alloc, dealloc, Layout}; use std::alloc::Layout;
use std::collections::HashSet;
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct DmAllocObject { pub struct DmAllocObject {
pub data: *mut u8, pub data: *mut u8,
pub units: HashSet<usize>,
pub size: usize, pub size: usize,
pub layout: Layout, pub layout: Layout,
pub implementation: Rc<DmImplementation>, pub implementation: Rc<DmImplementation>,
} }
impl DmAllocObject {
pub fn new(size: usize, implementation: Rc<DmImplementation>) -> Self {
let layout = Layout::from_size_align(size, 1).unwrap();
DmAllocObject {
data: unsafe { alloc(layout) },
units: HashSet::new(),
size,
layout,
implementation,
}
}
}
impl Drop for DmAllocObject {
fn drop(&mut self) {
unsafe {
dealloc(self.data, self.layout);
}
}
}
pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -> DvmValue { pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -> DvmValue {
let data_size = dm_field.dm_type().size_in_bytes(); let data_size = dm_field.dm_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);
@ -52,13 +29,13 @@ pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -
DmType::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(),
)), )),
DmType::Boolean => DvmValue::Boolean(raw_data[0] != 0), DmType::Boolean => DvmValue::Boolean(raw_data[0] == 1),
DmType::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))
} }
DmType::Unit => DvmValue::Uninit, DmType::Unit => DvmValue::Unit,
} }
} }

View File

@ -11,583 +11,381 @@ use crate::vm::dvm_value::DvmValue;
use crate::vm::lib::{DmConstant, DmLib}; use crate::vm::lib::{DmConstant, DmLib};
use crate::vm::mem::{get_field_value, DmAllocObject}; 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 op_codes::*; use op_codes::*;
use std::alloc::{alloc, dealloc, Layout}; 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};
pub type PlatformFunction = pub type PlatformFunction = fn(args: Vec<DvmValue>, &mut DmVirtualMachine) -> DvmValue;
fn(args: Vec<DvmValue>, state: &mut DvmState, context: &DvmContext) -> DvmValue;
enum CallFrame { enum CallFrame {
PlatformCall(CallFrameInfo), PlatformCall(PlatformCallFrame),
DeimosCall(CallFrameInfo), DeimosCall(DeimosCallFrame),
} }
struct CallFrameInfo { pub struct PlatformCallFrame {
fn_fqn: String, pub name: String,
pub args: Vec<DvmValue>,
} }
pub struct DvmContext { struct DeimosCallFrame {
return_address: usize,
}
pub struct DmVirtualMachine {
libs: Vec<DmLib>, libs: Vec<DmLib>,
functions: HashMap<String, Rc<DmFn>>, functions: HashMap<String, Rc<DmFn>>,
platform_functions: HashMap<String, Rc<PlatformFunction>>, platform_functions: HashMap<String, PlatformFunction>,
} ip: usize,
impl DvmContext {
pub fn new() -> Self {
DvmContext {
libs: Vec::new(),
functions: HashMap::new(),
platform_functions: HashMap::new(),
}
}
pub fn load_functions(&mut self, libs: &Vec<DmLib>) {
for lib in libs {
for lib_fn in &lib.functions {
self.functions
.insert(lib_fn.fqn().to_string(), lib_fn.clone());
}
for interface_function in lib
.interfaces
.iter()
.flat_map(|interface| interface.get_functions())
{
self.functions.insert(
interface_function.fqn().to_string(),
interface_function.clone(),
);
}
for implementation_function in lib
.implementations
.iter()
.flat_map(|implementation| &implementation.functions)
{
self.functions.insert(
implementation_function.fqn().to_string(),
implementation_function.clone(),
);
}
}
}
pub fn fn_by_fqn(&self, fqn: &str) -> Option<Rc<DmFn>> {
self.functions.get(fqn).cloned()
}
pub fn platform_fn_by_fqn(&self, fqn: &str) -> Option<Rc<PlatformFunction>> {
self.platform_functions.get(fqn).cloned()
}
}
pub struct DvmState {
call_stack: Vec<CallFrame>, call_stack: Vec<CallFrame>,
registers: Vec<DvmValue>, registers: Vec<DvmValue>,
register_state_stack: Vec<Vec<DvmValue>>, register_state_stack: Vec<Vec<DvmValue>>,
} }
impl DvmState { fn load_functions(destination: &mut HashMap<String, Rc<DmFn>>, libs: &Vec<DmLib>) {
pub fn new() -> Self { for module in libs {
DvmState { for lib_fn in &module.functions {
call_stack: Vec::new(), 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(),
);
}
}
}
impl DmVirtualMachine {
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(), registers: 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 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>) -> Option<DvmValue> {
// save current state
self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame {
return_address: self.ip,
}));
self.register_state_stack.push(self.registers.clone());
// zero registers and make sure there are enough for dm_function
self.registers.clear();
if self.registers.len() < args.len() {
self.registers.resize(args.len(), DvmValue::Unit);
} }
}
}
pub fn call_fn( // push args
state: &mut DvmState, for i in 0..args.len() {
context: &DvmContext, self.registers.insert(i, args[i].clone());
dm_fn: &DmFn, }
args: Vec<DvmValue>,
) -> DvmValue {
// save current state
state.call_stack.push(CallFrame::DeimosCall(CallFrameInfo {
fn_fqn: dm_fn.fqn().to_string(),
}));
state.register_state_stack.push(state.registers.clone());
// zero registers and make sure there are enough for dm_function // run the byte code
state.registers.clear(); self.run_raw(&dm_function.byte_code);
if state.registers.len() < dm_fn.number_used_registers() {
state // restore state
.registers self.registers = self.register_state_stack.pop().unwrap();
.resize(dm_fn.number_used_registers(), DvmValue::Uninit); if let CallFrame::DeimosCall(deimos_call_frame) = self.call_stack.pop().unwrap() {
self.ip = deimos_call_frame.return_address;
}
// return result
self.registers.get(0).map(|x| x.clone())
} }
// push args pub fn run_raw(&mut self, code: &Vec<u8>) {
for arg in args {
state.registers.push(arg);
}
// run the byte code
run_byte_code(state, context, &dm_fn.byte_code());
// restore state
state.registers = state.register_state_stack.pop().unwrap();
state.call_stack.pop();
// get return value
if let Some(return_register) = dm_fn.return_register() {
state
.registers
.get(return_register as usize)
.map(|m| m.clone())
.unwrap()
} else {
DvmValue::Void
}
}
macro_rules! next_8 {
( $byte_code: expr, $T: ident ) => {
$byte_code.next().unwrap() as $T
};
}
macro_rules! next_32_le {
( $byte_code: expr, $T: ident ) => {
next_8!($byte_code, $T)
+ (next_8!($byte_code, $T) << 8)
+ (next_8!($byte_code, $T) << 16)
+ (next_8!($byte_code, $T) << 24)
};
}
macro_rules! next_64_le {
( $byte_code: expr, $T: ident ) => {
next_8!($byte_code, $T)
+ (next_8!($byte_code, $T) << 8)
+ (next_8!($byte_code, $T) << 16)
+ (next_8!($byte_code, $T) << 24)
+ (next_8!($byte_code, $T) << 32)
+ (next_8!($byte_code, $T) << 40)
+ (next_8!($byte_code, $T) << 48)
+ (next_8!($byte_code, $T) << 56)
};
}
macro_rules! read_array_u8 {
( $iter: expr ) => {{
let arr_length = next_8!($iter, u8);
let mut arr = Vec::with_capacity(arr_length as usize);
let mut i = 0; let mut i = 0;
while i < arr_length { while i < code.len() {
arr.push(next_8!($iter, u8)); let op_code = code[i];
i += 1; println!("op_code: {:#04x}", op_code);
} match code[i] {
arr MOV_INT => {
}}; let target_register = code[i + 1] as usize;
} let operand = get_32_le!(code, i, 2, u32);
self.registers
.insert(target_register, DvmValue::Int(operand as i32));
i += 6;
}
MOV_LONG => {
let target_register = code[i + 1] as usize;
let operand = get_64_le!(code, i, 2, u64);
self.registers
.insert(target_register, DvmValue::Long(operand as i64));
i += 10;
}
MOV_DOUBLE => {
unimplemented!();
}
MOV_REGISTER => {
let target_register = code[i + 1] as usize;
let source_register = code[i + 2] as usize;
let source_value = self.registers.get(source_register).unwrap();
self.registers.insert(target_register, source_value.clone());
i += 3;
}
ALLOC => {
i += 1;
let target_register = code[i] as usize;
i += 1;
let alloc_size = 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();
macro_rules! read_string { let implementation = self
( $iter: expr ) => {{ .libs
let str_length = next_32_le!($iter, usize); .iter()
let mut str_raw: Vec<u8> = Vec::new(); .find_map(|lib| {
let mut i = 0; lib.implementations
while i < str_length { .iter()
str_raw.push($iter.next().unwrap()); .find(|implementation| implementation.fqn == implementation_name)
i += 1; })
} .expect(&format!(
String::from_utf8(str_raw).unwrap() "Implementation not found: {}",
}}; implementation_name
} ));
macro_rules! write_string { let layout = Layout::from_size_align(alloc_size, 1).unwrap();
( $raw_ptr: expr, $s: expr ) => { let raw_data_ptr;
for (i, b) in $s.bytes().enumerate() { unsafe {
unsafe { raw_data_ptr = alloc(layout);
$raw_ptr.add(i).write(b);
}
}
};
}
macro_rules! write_bytes {
( $ptr: expr, $offset: expr, $src: expr ) => {
for (i, &b) in $src.iter().enumerate() {
unsafe {
$ptr.add($offset + i).write(b);
}
}
};
}
pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8]) {
let mut iter = byte_code.iter().cloned();
while let Some(op_code) = iter.next() {
match op_code {
MOV_INT => {
let target_register = next_8!(iter, usize);
let operand = next_32_le!(iter, u32) as i32;
state
.registers
.insert(target_register, DvmValue::Int(operand));
}
MOV_LONG => {
let target_register = next_8!(iter, usize);
let operand = next_64_le!(iter, u64) as i64;
state
.registers
.insert(target_register, DvmValue::Long(operand));
}
MOV_DOUBLE => {
let target_register = next_8!(iter, usize);
let operand = next_64_le!(iter, u64) as f64;
state
.registers
.insert(target_register, DvmValue::Double(operand));
}
MOV_REGISTER => {
let target_register = next_8!(iter, usize);
let source_register = next_8!(iter, usize);
let source_value = state.registers.get(source_register).unwrap();
state
.registers
.insert(target_register, source_value.clone())
}
ALLOC => {
let target_register = next_8!(iter, usize);
let alloc_size = next_32_le!(iter, usize);
let impl_name = read_string!(iter);
let implementation = context
.libs
.iter()
.find_map(|lib| {
lib.implementations
.iter()
.find(|implementation| implementation.fqn == impl_name)
})
.expect(&format!("Implementation not found: {}", impl_name));
let dm_alloc_object = DmAllocObject::new(alloc_size, implementation.clone());
let dvm_pointer = DvmValue::Pointer(Rc::new(dm_alloc_object));
state.registers.insert(target_register, dvm_pointer);
}
DEALLOC => {
let target_register = next_8!(iter, usize);
let dm_alloc_object = state.registers.remove(target_register).expect_pointer();
drop(dm_alloc_object); // explicit
}
MOV_INT_TO => {
let target_register = next_8!(iter, usize);
let offset = next_32_le!(iter, usize);
let operand = next_32_le!(iter, u32) as i32;
let dm_alloc_object = state
.registers
.get(target_register)
.unwrap()
.expect_pointer();
write_bytes!(dm_alloc_object.data, offset, operand.to_ne_bytes());
}
MOV_LONG_TO => {
todo!()
}
MOV_DOUBLE_TO => {
todo!()
}
MOV_REGISTER_TO => {
// Moves the value from the source register to the object pointed to by the target
// register, at the given offset.
let target_register = next_8!(iter, usize);
let offset = next_32_le!(iter, usize);
let source_register = next_8!(iter, usize);
let target_alloc_object = state
.registers
.get(target_register)
.unwrap()
.expect_pointer();
let source_value = state.registers.get(source_register).unwrap();
match source_value {
DvmValue::Int(i) => {
write_bytes!(target_alloc_object.data, offset, i.to_ne_bytes());
} }
DvmValue::Byte(b) => unsafe { let dm_alloc_object = DmAllocObject {
target_alloc_object.data.add(offset).write(*b); data: raw_data_ptr,
}, layout,
DvmValue::Long(l) => { size: alloc_size,
write_bytes!(target_alloc_object.data, offset, l.to_ne_bytes()); implementation: implementation.clone(),
} };
DvmValue::Double(d) => {
write_bytes!(target_alloc_object.data, offset, d.to_ne_bytes()); let dvm_value = DvmValue::Pointer(Rc::new(dm_alloc_object));
} self.registers.insert(target_register, dvm_value);
DvmValue::Boolean(b) => unsafe { }
target_alloc_object.data.add(offset).write(*b as u8); DEALLOC => {
}, todo!()
DvmValue::Pointer(source_alloc_object) => { }
let source_ptr = Rc::into_raw(source_alloc_object.clone()); MOV_INT_TO => {
write_bytes!( todo!()
target_alloc_object.data, }
offset, MOV_REGISTER_TO => {
(source_ptr as usize).to_ne_bytes() i += 1;
); let target_register = code[i] as usize;
} i += 1;
DvmValue::Uninit => { let offset = get_32_le!(code, i, 0, isize);
panic!("Cannot move DvmValue::Uninit to object.") i += 4;
} let source_register = code[i] as usize;
DvmValue::Void => { i += 1;
panic!("Cannot move DvmValue::Void to object.")
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 => {
MOV_CONST => { i += 1;
// TODO: reduce the complexity of this. let target_register = code[i] as usize;
// Perhaps the target register should just contain a ptr where the data is written. 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;
// Decode let lib_name = String::from_utf8(lib_name_raw).unwrap();
let target_register = next_8!(iter, usize); // must contain an allocated StringImpl
let lib_name = read_string!(iter);
let const_id = next_8!(iter, usize);
let pointer_impl_register = next_8!(iter, usize);
let byte_array_impl_register = next_8!(iter, usize);
// Get constant if let Some(lib) = self.libs.iter().find(|&lib| lib.name == lib_name) {
let Some(lib) = context.libs.iter().find(|lib| lib.name == lib_name) else { let constant = &lib.constants[const_id];
panic!("Could not find lib with name: {}", lib_name); match constant {
}; DmConstant::String(s) => {
let constant = lib.constants.get(const_id).unwrap(); let alloc_fn = self.get_fn_by_fqn("std::unsafe::mem::alloc")
let DmConstant::String(s) = constant; .expect("Could not find std::unsafe::mem::alloc");
let alloc_size_arg = DvmValue::Long(s.len() as i64);
// Get allocated PointerImpl let alloc_return_value = self.call_fn(&alloc_fn, vec![alloc_size_arg]).unwrap();
let pointer_impl = state let DvmValue::Pointer(pointer_object) = alloc_return_value else {
.registers panic!("Expected std::unsafe::mem::alloc to return DvmValue::Pointer, but got: {:?}", alloc_return_value);
.get(pointer_impl_register) };
.unwrap() let raw_address_field = pointer_object.implementation.get_field("raw_address", &pointer_object)
.expect_pointer(); .expect("Could not get PointerImpl.raw_address field.");
unsafe {
// Init PointerImpl object let raw_address_value = get_field_value(&raw_address_field, &pointer_object);
let pointer_impl_ctor_0_fn = context let DvmValue::Long(raw_address) = raw_address_value else {
.functions panic!("Expected PointerImpl.raw_address to be a DvmValue::Long, but got: {:?}", raw_address_value);
.get("std::unsafe::PointerImpl::_ctor_0") };
.expect("Could not find std::unsafe::PointerImpl::_ctor_0"); let ptr = raw_address as usize as *mut u8;
call_fn( for (j, b) in s.bytes().enumerate() {
state, ptr.offset(j as isize).write(b);
context, }
pointer_impl_ctor_0_fn, self.registers.insert(target_register, DvmValue::Pointer(pointer_object));
vec![ }
DvmValue::Pointer(pointer_impl.clone()), }
DvmValue::Long(s.len() as i64), _ => {
], panic!("Invalid constant type");
); }
}
// Get std::unsafe::PointerImpl.raw_address field as *mut u8 } else {
let raw_ptr = unsafe { panic!("Could not find lib: {}", lib_name);
get_field_value( }
pointer_impl
.implementation
.get_field("raw_address", &pointer_impl)
.expect("Could not get PointerImpl.raw_address field."),
&pointer_impl,
)
} }
.expect_long() as usize as *mut u8; PLATFORM_CALL => {
i += 1;
// Write the constant bytes to the raw_ptr let symbol_name_length = get_32_le!(code, i, 0, usize);
write_string!(raw_ptr, s); i += 4;
// Get allocated ArrayImpl<Byte> from byte_array_impl_register let symbol_name_raw = code[i..(i + symbol_name_length)].to_vec();
let byte_array_impl = state i += symbol_name_length;
.registers
.get(byte_array_impl_register)
.unwrap()
.expect_pointer();
// Init ArrayImpl<Byte> let symbol_name = String::from_utf8(symbol_name_raw).unwrap();
let array_ctor_0_fn = context
.functions
.get("std::core::ArrayImpl::_ctor_1")
.expect("Could not find std::core::ArrayImpl::_ctor_1");
call_fn(
state,
context,
array_ctor_0_fn,
vec![
DvmValue::Pointer(byte_array_impl.clone()), // self
DvmValue::Pointer(pointer_impl.clone()), // PointerImpl
DvmValue::Int(s.len() as i32), // length
],
);
// Get allocated StringImpl from string_impl_register let return_register = code[i + 1] as usize;
let string_impl = state i += 1;
.registers
.get(target_register)
.unwrap()
.expect_pointer();
// Init StringImpl let arg_registers_length = code[i] as usize;
let string_impl_ctor_0_fn = context i += 1;
.functions
.get("std::core::StringImpl::_ctor_0")
.expect("Could not find std::core::StringImpl::_ctor_0");
call_fn(
state,
context,
string_impl_ctor_0_fn,
vec![
DvmValue::Pointer(string_impl.clone()),
DvmValue::Pointer(byte_array_impl.clone()),
],
);
}
ALLOC_RAW => {
// Allocates a raw number of bytes, with the number of bytes determined by the value
// of the source register. The address is stored in the target register as a
// DvmValue::Long.
let target_register = next_8!(iter, usize);
let source_register = next_8!(iter, usize);
let number_of_bytes =
state.registers.get(source_register).unwrap().expect_long() as usize;
let layout = Layout::from_size_align(number_of_bytes, 0).unwrap();
let ptr = unsafe { alloc(layout) };
state
.registers
.insert(target_register, DvmValue::Long(ptr as i64))
}
DEALLOC_RAW => {
// Deallocates a raw number of bytes at an address, with the number of bytes
// determined by the value in the source register, and the address stored in the
// target register.
let target_register = next_8!(iter, usize);
let source_register = next_8!(iter, usize);
let number_of_bytes =
state.registers.get(source_register).unwrap().expect_long() as usize;
let layout = Layout::from_size_align(number_of_bytes, 0).unwrap(); let arg_registers = code[i..(i + arg_registers_length)].to_vec();
let ptr = i += arg_registers_length;
state.registers.get(target_register).unwrap().expect_long() as usize as *mut u8;
unsafe { let mut args = Vec::new();
dealloc(ptr, layout); for arg_register in arg_registers {
let register_value = self.registers.get(arg_register as usize).unwrap();
args.push(register_value.clone());
}
let platform_function_result = self.platform_functions.get(&symbol_name);
if platform_function_result.is_none() {
panic!("Unknown platform function {}", symbol_name);
}
let platform_function = platform_function_result.unwrap();
let call_result = platform_function(args, self);
self.registers.insert(return_register, call_result);
} }
state.registers.insert(target_register, DvmValue::Uninit); INVOKE_FN => {
} unimplemented!()
PLATFORM_CALL => {
// Calls a platform function. The result of the platform call is stored in the
// specified return register.
let symbol_name = read_string!(iter);
let return_register = next_8!(iter, usize);
let arg_registers = read_array_u8!(iter);
let mut args = Vec::with_capacity(arg_registers.len());
for arg_register in arg_registers {
let value = state.registers.get(arg_register as usize).unwrap();
args.push(value.clone());
} }
INVOKE_VIRTUAL => {
let platform_function = context unimplemented!();
.platform_functions
.get(&symbol_name)
.unwrap()
.clone();
state
.call_stack
.push(CallFrame::PlatformCall(CallFrameInfo {
fn_fqn: symbol_name,
}));
let call_result = platform_function(args, state, context);
state.registers.insert(return_register, call_result);
state.call_stack.pop();
}
INVOKE_FN => {
let symbol_name = read_string!(iter);
let return_register = next_8!(iter, usize);
let arg_registers = read_array_u8!(iter);
let mut args = Vec::with_capacity(arg_registers.len());
for arg_register in arg_registers {
let value = state.registers.get(arg_register as usize).unwrap();
args.push(value.clone());
} }
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 dm_fn = context.functions.get(&symbol_name).unwrap(); let method_name = String::from_utf8(name_raw).unwrap();
let call_result = call_fn(state, context, dm_fn, args);
state.registers.insert(return_register, call_result);
}
INVOKE_VIRTUAL => {
let symbol_name = read_string!(iter);
let return_register = next_8!(iter, usize);
let arg_registers = read_array_u8!(iter);
let mut args = Vec::with_capacity(arg_registers.len()); let method = self
for arg_register in arg_registers { .get_fn_by_fqn(&method_name)
let value = state.registers.get(arg_register as usize).unwrap(); .expect(&format!("Could not find method: {}", method_name));
args.push(value.clone());
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 => {
let self_obj = args.get(0).unwrap().expect_pointer(); unimplemented!()
let method = self_obj }
.implementation RETURN => {
.get_method(&symbol_name, &self_obj) i += 1;
.expect(&format!("Could not find method: {}", symbol_name)); }
let dm_fn = method.dm_fn(); RETURN_REGISTER => {
unimplemented!()
let call_result = call_fn(state, context, dm_fn, args); }
state.registers.insert(return_register, call_result); op_code => panic!("Invalid or unimplemented op code: {:#04x}", op_code),
}
INVOKE_DYNAMIC => {
unimplemented!("INVOKE_DYNAMIC is not yet supported and may never be.")
}
MOV_SIZE_OF => {
todo!()
}
MULTIPLY => {
todo!()
}
op_code => {
panic!("Invalid op_code: {}", op_code);
} }
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod run_code_tests { mod dvm_run_tests {
use super::*; use super::*;
macro_rules! assert_register { macro_rules! assert_register {
( $expected: expr, $state: expr, $register_number: expr ) => { ( $expected: expr, $register: expr ) => {
assert_eq!( assert_eq!($expected, $register.unwrap().clone());
$expected,
$state.registers.get($register_number).unwrap().clone()
);
}; };
} }
fn setup() -> (DvmState, DvmContext) {
(DvmState::new(), DvmContext::new())
}
#[test] #[test]
fn mov_1_as_int() { fn mov_1_as_int() {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 0, 1); add_mov_int(&mut code, 0, 1);
let (mut state, context) = setup(); let mut vm = DmVirtualMachine::new(Vec::new());
run_byte_code(&mut state, &context, &code); vm.run_raw(&code);
assert_register!(DvmValue::Int(1), state, 0); assert_register!(DvmValue::Int(1), vm.registers.get(0));
} }
#[test] #[test]
fn move_65535_as_int() { fn move_65535_as_int() {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 0, 0xffff); add_mov_int(&mut code, 0, 0xffff);
let (mut state, context) = setup(); let mut vm = DmVirtualMachine::new(Vec::new());
run_byte_code(&mut state, &context, &code); vm.run_raw(&code);
assert_register!(DvmValue::Int(0xffff), state, 0); assert_register!(DvmValue::Int(0xffff), vm.registers.get(0));
} }
#[test] #[test]
fn move_int_max_as_int() { fn move_int_max_as_int() {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 0, 0x0fff_ffff); add_mov_int(&mut code, 0, 0x0fff_ffff);
let (mut state, context) = setup(); let mut vm = DmVirtualMachine::new(Vec::new());
run_byte_code(&mut state, &context, &code); vm.run_raw(&code);
assert_register!(DvmValue::Int(0x0fff_ffff), state, 0); assert_register!(DvmValue::Int(0x0fff_ffff), vm.registers.get(0));
} }
#[test] #[test]
@ -595,9 +393,37 @@ mod run_code_tests {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 1, 1); add_mov_int(&mut code, 1, 1);
add_mov_register(&mut code, 0, 1); add_mov_register(&mut code, 0, 1);
let (mut state, context) = setup(); let mut vm = DmVirtualMachine::new(Vec::new());
state.registers.resize(2, DvmValue::Uninit); vm.registers.resize(2, DvmValue::Unit);
run_byte_code(&mut state, &context, &code); vm.run_raw(&code);
assert_register!(DvmValue::Int(1), state, 0); assert_register!(DvmValue::Int(1), vm.registers.get(0));
}
#[test]
#[ignore]
fn mov_int_to_register_as_address() {
let mut code = Vec::new();
add_alloc(&mut code, 0, 4);
add_mov_int_to(&mut code, 0, 0, 0xff);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.run_raw(&code);
let actual = vm.registers.get(0).unwrap().clone();
match actual {
DvmValue::Pointer(value_box) => {
assert_eq!(DvmValue::Int(0xff), *value_box);
}
_ => panic!("Target register is not a pointer"),
}
}
#[test]
#[ignore]
fn alloc_and_dealloc_expect_register_cleared() {
let mut code = Vec::new();
add_alloc(&mut code, 0, 4);
add_dealloc(&mut code, 0);
let mut vm = DmVirtualMachine::new(Vec::new());
vm.run_raw(&code);
assert_register!(DvmValue::Unit, vm.registers.get(0));
} }
} }

View File

@ -11,49 +11,37 @@ pub enum DmObjectType {
#[derive(Debug, Eq)] #[derive(Debug, Eq)]
pub struct DmFn { pub struct DmFn {
fqn: String, pub fqn: String,
short_name: String, pub short_name: String,
byte_code: Vec<u8>, pub byte_code: Vec<u8>,
number_used_registers: usize, pub number_used_registers: usize,
return_register: Option<u8>,
} }
impl DmFn { impl DmFn {
pub fn new( pub fn new(fqn: &str, short_name: &str, byte_code: Vec<u8>, number_used_registers: usize) -> Self {
fqn: &str,
short_name: &str,
byte_code: Vec<u8>,
number_used_registers: usize,
return_register: Option<u8>,
) -> Self {
DmFn { DmFn {
fqn: fqn.to_string(), fqn: fqn.to_string(),
short_name: short_name.to_string(), short_name: short_name.to_string(),
byte_code, byte_code,
number_used_registers, number_used_registers
return_register,
} }
} }
pub fn fqn(&self) -> &str { pub fn fqn(&self) -> &str {
self.fqn.as_str() self.fqn.as_str()
} }
pub fn short_name(&self) -> &str { pub fn short_name(&self) -> &str {
self.short_name.as_str() self.short_name.as_str()
} }
pub fn byte_code(&self) -> &Vec<u8> { pub fn byte_code(&self) -> &Vec<u8> {
&self.byte_code &self.byte_code
} }
pub fn number_used_registers(&self) -> usize { pub fn number_used_registers(&self) -> usize {
self.number_used_registers self.number_used_registers
} }
pub fn return_register(&self) -> Option<u8> {
self.return_register
}
} }
impl PartialEq for DmFn { impl PartialEq for DmFn {
@ -80,11 +68,7 @@ impl DmMethod {
dm_fn: Rc::new(dm_fn), dm_fn: Rc::new(dm_fn),
implements, implements,
} }
} }
pub fn dm_fn(&self) -> &DmFn {
&self.dm_fn
}
} }
#[derive(Debug, Eq)] #[derive(Debug, Eq)]
@ -110,27 +94,27 @@ impl DmInterface {
virtual_methods: Vec::new(), virtual_methods: Vec::new(),
} }
} }
pub fn fqn(&self) -> &str { pub fn fqn(&self) -> &str {
self.fqn.as_str() self.fqn.as_str()
} }
pub fn short_name(&self) -> &str { pub fn short_name(&self) -> &str {
self.short_name.as_str() self.short_name.as_str()
} }
pub fn add_function(&mut self, dm_fn: DmFn) { pub fn add_function(&mut self, dm_fn: DmFn) {
self.functions.push(Rc::new(dm_fn)); self.functions.push(Rc::new(dm_fn));
} }
pub fn get_functions(&self) -> Vec<Rc<DmFn>> { pub fn get_functions(&self) -> Vec<Rc<DmFn>> {
self.functions.clone() self.functions.clone()
} }
pub fn add_method(&mut self, dm_virtual_method: DmVirtualMethod) { pub fn add_method(&mut self, dm_virtual_method: DmVirtualMethod) {
self.virtual_methods.push(Rc::new(dm_virtual_method)); self.virtual_methods.push(Rc::new(dm_virtual_method));
} }
pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmMethod>> { pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmMethod>> {
if self if self
.virtual_methods .virtual_methods
@ -142,7 +126,7 @@ impl DmInterface {
} }
None None
} }
pub fn get_virtual_methods(&self) -> Vec<Rc<DmVirtualMethod>> { pub fn get_virtual_methods(&self) -> Vec<Rc<DmVirtualMethod>> {
self.virtual_methods.clone() self.virtual_methods.clone()
} }
@ -191,7 +175,7 @@ impl DmImplementation {
fields: Vec::new(), fields: Vec::new(),
} }
} }
pub fn interface(&self) -> Option<Rc<DmInterface>> { pub fn interface(&self) -> Option<Rc<DmInterface>> {
self.interface.clone() self.interface.clone()
} }
@ -216,7 +200,7 @@ impl DmImplementation {
pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmField> { pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmField> {
self.fields.iter().find(|field| field.name == name) self.fields.iter().find(|field| field.name == name)
} }
pub fn size_in_bytes(&self) -> usize { pub fn size_in_bytes(&self) -> usize {
self.fields.iter().map(|field| field.size_in_bytes()).sum() self.fields.iter().map(|field| field.size_in_bytes()).sum()
} }
@ -251,24 +235,24 @@ impl PartialEq for DmField {
impl DmField { impl DmField {
pub fn new(name: &str, dm_type: DmType, data_offset: usize) -> Self { pub fn new(name: &str, dm_type: DmType, data_offset: usize) -> Self {
DmField { DmField {
name: name.to_string(), name: name.to_string(),
dm_type, dm_type,
data_offset, data_offset
} }
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
pub fn dm_type(&self) -> &DmType { pub fn dm_type(&self) -> &DmType {
&self.dm_type &self.dm_type
} }
pub fn data_offset(&self) -> usize { pub fn data_offset(&self) -> usize {
self.data_offset self.data_offset
} }
pub fn size_in_bytes(&self) -> usize { pub fn size_in_bytes(&self) -> usize {
self.dm_type.size_in_bytes() self.dm_type.size_in_bytes()
} }

View File

@ -39,14 +39,18 @@ pub const MOV_REGISTER_TO: u8 = 0x0a;
pub const MOV_CONST: u8 = 0x0b; pub const MOV_CONST: u8 = 0x0b;
pub const ALLOC_RAW: u8 = 0x0d; pub const ALLOC_RAW: u8 = 0x0c;
pub const DEALLOC_RAW: u8 = 0x0e; 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_FN: u8 = 0x11;
pub const INVOKE_VIRTUAL: u8 = 0x12; pub const INVOKE_VIRTUAL: u8 = 0x12;
pub const INVOKE_METHOD: u8 = 0x13;
pub const INVOKE_DYNAMIC: u8 = 0x14; 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 MOV_SIZE_OF: u8 = 0x30;
pub const MULTIPLY: u8 = 0x40; pub const MULTIPLY: u8 = 0x40;
@ -83,9 +87,15 @@ pub fn add_alloc(code: &mut Vec<u8>, register: u8, size: u32, implementation_nam
push_string!(code, implementation_name); push_string!(code, implementation_name);
} }
pub fn add_alloc_raw_from(code: &mut Vec<u8>, target_register: u8, source_register: u8) { pub fn add_alloc_raw(code: &mut Vec<u8>, target_register: u8, size: u32) {
code.push(ALLOC_RAW); code.push(ALLOC_RAW);
code.push(target_register); 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); push_number!(code, source_register);
} }
@ -149,6 +159,25 @@ pub fn add_invoke_fn(code: &mut Vec<u8>, fn_name: &str, return_register: u8, arg
} }
} }
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) { pub fn add_mov_size_of(code: &mut Vec<u8>, target_register: u8, source_register: u8) {
code.push(MOV_SIZE_OF); code.push(MOV_SIZE_OF);
code.push(target_register); code.push(target_register);

View File

@ -1,84 +1,96 @@
use crate::vm::dvm_value::DvmValue; use crate::vm::dvm_value::DvmValue;
use crate::vm::mem::{get_field_value, DmAllocObject}; use crate::vm::mem::{get_field_value, DmAllocObject};
use crate::vm::{DvmContext, DvmState}; use crate::vm::DmVirtualMachine;
use std::rc::Rc; use std::rc::Rc;
pub fn dm_print(args: Vec<DvmValue>, _state: &mut DvmState, _context: &DvmContext) -> DvmValue { pub fn dm_print(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
if args.len() != 1 { if args.len() != 1 {
return DvmValue::Void; // TODO: make exception return DvmValue::Unit; // TODO: make exception
} }
unsafe { unsafe {
print!("{}", get_string(&args[0])); print!("{}", get_string(&args[0], vm));
} }
DvmValue::Void DvmValue::Unit
} }
pub fn dm_println(args: Vec<DvmValue>, _state: &mut DvmState, _context: &DvmContext) -> DvmValue { pub fn dm_println(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
if args.len() != 1 { if args.len() != 1 {
return DvmValue::Uninit; return DvmValue::Unit;
} }
unsafe { unsafe {
println!("{}", get_string(&args[0])); println!("{}", get_string(&args[0], vm));
} }
DvmValue::Void DvmValue::Unit
} }
unsafe fn get_string(dvm_value: &DvmValue) -> 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(),
DvmValue::Long(l) => l.to_string(), DvmValue::Long(l) => l.to_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(object) => convert_to_string(object.clone()), DvmValue::Pointer(alloc_object_rc) => convert_to_string(alloc_object_rc.clone(), vm),
DvmValue::Uninit => String::from("Uninit"), DvmValue::Unit => String::from("Unit"),
DvmValue::Void => String::from("Void"),
} }
} }
fn convert_to_string(alloc_object_rc: Rc<DmAllocObject>) -> String { unsafe fn convert_to_string(
alloc_object_rc: Rc<DmAllocObject>,
vm: &mut DmVirtualMachine,
) -> String {
if alloc_object_rc.implementation.fqn == "std::core::String" { if alloc_object_rc.implementation.fqn == "std::core::String" {
extract_string_from_string(alloc_object_rc.clone()) 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 { } else {
todo!("what happens if we don't have a String?") todo!("what happens if we don't have a String?")
} }
} }
fn extract_string_from_string(string_object: Rc<DmAllocObject>) -> String {
let bytes_field = string_object
.implementation
.get_field("bytes", &string_object)
.expect("Could not get String.bytes field.");
let bytes_object = unsafe { get_field_value(&bytes_field, &string_object) }.expect_pointer();
if bytes_object.implementation.fqn != "std::core::ArrayImpl" {
panic!("String.bytes field is not a std::core::ArrayImpl");
}
let pointer_field = bytes_object
.implementation
.get_field("pointer", &bytes_object)
.expect("Could not get ArrayImpl.pointer field.");
let pointer_object = unsafe { get_field_value(&pointer_field, &bytes_object) }.expect_pointer();
if pointer_object.implementation.fqn != "std::unsafe::PointerImpl" {
panic!("ArrayImpl.pointer is not a std::unsafe::PointerImpl");
}
let raw_address_field = pointer_object
.implementation
.get_field("raw_address", &pointer_object)
.expect("Could not get PointerImpl.raw_address field.");
let raw_address = unsafe { get_field_value(&raw_address_field, &pointer_object) }.expect_long();
let size_field = pointer_object
.implementation
.get_field("size", &pointer_object)
.expect("Could not get PointerImpl.size field.");
let size = unsafe { get_field_value(&size_field, &pointer_object) }.expect_long();
let raw_bytes_pointer = raw_address as usize as *mut u8;
let mut v: Vec<u8> = Vec::new();
for i in 0..(size as isize) {
v.push(unsafe { raw_bytes_pointer.offset(i).read() });
}
String::from_utf8(v).unwrap()
}