Much work on dvm implementation; not compiling yet.
This commit is contained in:
parent
21d4f6bb69
commit
a14eb550ce
@ -7,4 +7,8 @@ edition = "2021"
|
||||
name = "dmc"
|
||||
path = "src/bin/compiler/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "dm"
|
||||
path = "src/bin/dvm/main.rs"
|
||||
|
||||
[dependencies]
|
||||
|
14
src/bin/dvm/main.rs
Normal file
14
src/bin/dvm/main.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use std::process::exit;
|
||||
use deimos::vm::DmVirtualMachine;
|
||||
use deimos::vm::op_codes::{add_mov_int, add_platform_call_to};
|
||||
|
||||
fn main() {
|
||||
let mut code: Vec<u8> = Vec::new();
|
||||
add_mov_int(&mut code, 0, 42);
|
||||
add_platform_call_to(&mut code, &String::from("std::core::print"), 1, &vec![0u8]);
|
||||
let mut vm = DmVirtualMachine::new();
|
||||
if let Err(_) = vm.run(&mut code) {
|
||||
eprintln!("There was an exception.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
385
src/vm/mod.rs
385
src/vm/mod.rs
@ -1,37 +1,311 @@
|
||||
mod module;
|
||||
mod op_codes;
|
||||
mod platform;
|
||||
mod types;
|
||||
pub mod module;
|
||||
pub mod op_codes;
|
||||
pub mod platform;
|
||||
pub mod types;
|
||||
mod util;
|
||||
|
||||
use crate::vm::module::DmFunction;
|
||||
use crate::vm::platform::init_platform_functions;
|
||||
use op_codes::*;
|
||||
use platform::PlatformCallFrame;
|
||||
use std::alloc::{alloc_zeroed, dealloc, Layout};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Index;
|
||||
use types::DmType;
|
||||
use util::{get_32_le, get_64_le};
|
||||
|
||||
pub type PlatformFunction = fn(&mut PlatformCallFrame) -> Result<Option<(u64, DmType)>, String>;
|
||||
pub type PlatformFunction = fn(PlatformCallFrame) -> Result<Option<(u64, DmType)>, String>;
|
||||
|
||||
pub struct DmVirtualMachine {
|
||||
enum CallFrame<'a> {
|
||||
PlatformCall(PlatformCallFrame<'a>),
|
||||
DeimosCall(DeimosCallFrame<'a>)
|
||||
}
|
||||
|
||||
pub struct PlatformCallFrame<'a> {
|
||||
pub name: String,
|
||||
pub args: Vec<u64>,
|
||||
pub arg_types: Vec<DmType>,
|
||||
pub vm: &'a mut DmVirtualMachine<'a>
|
||||
}
|
||||
|
||||
struct DeimosCallFrame<'a> {
|
||||
return_address: usize,
|
||||
dm_function: &'a DmFunction
|
||||
}
|
||||
|
||||
struct RegisterSet {
|
||||
size: usize,
|
||||
registers: Vec<u64>,
|
||||
register_types: Vec<DmType>,
|
||||
platform_functions: HashMap<String, PlatformFunction>,
|
||||
}
|
||||
|
||||
impl DmVirtualMachine {
|
||||
pub fn call(
|
||||
&self,
|
||||
dm_function: &DmFunction,
|
||||
args: Vec<u64>,
|
||||
arg_types: Vec<DmType>,
|
||||
) -> Result<(u64, DmType), String> {
|
||||
run(&dm_function.byte_code, todo!(), todo!());
|
||||
todo!()
|
||||
type RegisterValue = (u64, DmType);
|
||||
|
||||
impl RegisterSet {
|
||||
fn new(size: usize) -> RegisterSet {
|
||||
RegisterSet {
|
||||
size,
|
||||
registers: vec![0; size],
|
||||
register_types: vec![DmType::Unit; size],
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, register_number: usize) -> RegisterValue {
|
||||
(self.registers[register_number], self.register_types[register_number])
|
||||
}
|
||||
|
||||
fn set_u32(&mut self, register_number: usize, value: u32, dm_type: DmType) {
|
||||
self.registers[register_number] = value as u64;
|
||||
self.register_types[register_number] = dm_type;
|
||||
}
|
||||
|
||||
fn set_u64(&mut self, register_number: usize, value: u64, dm_type: DmType) {
|
||||
self.registers[register_number] = value;
|
||||
self.register_types[register_number] = dm_type;
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.registers = vec![0; self.size];
|
||||
self.register_types = vec![DmType::Unit; self.size];
|
||||
}
|
||||
|
||||
fn ensure_capacity(&mut self, size: usize) {
|
||||
self.registers.resize(size, 0);
|
||||
self.register_types.resize(size, DmType::Unit);
|
||||
}
|
||||
|
||||
fn iter(&self) -> RegisterSetIterator {
|
||||
RegisterSetIterator::new(&self.registers, &self.register_types)
|
||||
}
|
||||
}
|
||||
|
||||
struct RegisterSetIterator<'a> {
|
||||
i: usize,
|
||||
registers: &'a Vec<u64>,
|
||||
register_types: &'a Vec<DmType>,
|
||||
}
|
||||
|
||||
impl RegisterSetIterator<'_> {
|
||||
fn new<'a>(registers: &'a Vec<u64>, register_types: &'a Vec<DmType>) -> RegisterSetIterator<'a> {
|
||||
RegisterSetIterator {
|
||||
i: 0usize,
|
||||
registers,
|
||||
register_types
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for RegisterSetIterator<'a> {
|
||||
type Item = RegisterValue;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.i < self.registers.len() {
|
||||
let some = Some((self.registers[self.i], self.register_types[self.i]));
|
||||
self.i += 1;
|
||||
some
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RegisterSet {
|
||||
fn clone(&self) -> Self {
|
||||
RegisterSet {
|
||||
size: self.size,
|
||||
registers: self.registers.clone(),
|
||||
register_types: self.register_types.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DmVirtualMachine<'a> {
|
||||
platform_functions: HashMap<String, PlatformFunction>,
|
||||
ip: usize,
|
||||
call_stack: Vec<CallFrame<'a>>,
|
||||
register_set: RegisterSet,
|
||||
register_state_stack: Vec<RegisterSet>,
|
||||
}
|
||||
|
||||
impl DmVirtualMachine<'_> {
|
||||
pub fn new<'a>() -> DmVirtualMachine<'a> {
|
||||
DmVirtualMachine {
|
||||
ip: 0,
|
||||
register_set: RegisterSet::new(0),
|
||||
platform_functions: init_platform_functions(),
|
||||
call_stack: Vec::new(),
|
||||
register_state_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call<const ArgLen: usize>(
|
||||
&mut self,
|
||||
dm_function: &DmFunction,
|
||||
args: [u64; ArgLen],
|
||||
arg_types: [DmType; ArgLen],
|
||||
) -> Result<(u64, DmType), String> {
|
||||
// save current state
|
||||
self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame {
|
||||
return_address: self.ip,
|
||||
dm_function
|
||||
}));
|
||||
self.register_state_stack.push(self.register_set.clone());
|
||||
|
||||
// zero registers and make sure there are enough for dm_function
|
||||
self.register_set.clear();
|
||||
self.register_set.ensure_capacity(dm_function.num_registers);
|
||||
|
||||
// push args
|
||||
for i in 0..args.len() {
|
||||
let arg = args[i];
|
||||
let arg_type = arg_types[i];
|
||||
self.register_set.set_u64(i, arg, arg_type);
|
||||
}
|
||||
|
||||
// run the byte code
|
||||
let call_result = self.run(&dm_function.byte_code);
|
||||
|
||||
// restore state
|
||||
self.register_set = self.register_state_stack.pop().unwrap();
|
||||
if let CallFrame::DeimosCall(deimos_call_frame) = self.call_stack.pop().unwrap() {
|
||||
self.ip = deimos_call_frame.return_address;
|
||||
}
|
||||
|
||||
// return result
|
||||
if let Err(_) = call_result {
|
||||
Err(String::from(format!("Failed to execute function {}", &dm_function.name)))
|
||||
} else {
|
||||
Ok(self.register_set.get(0))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self, code: &Vec<u8>) -> Result<(), ()> {
|
||||
let mut i = 0;
|
||||
while i < code.len() {
|
||||
match code[i] {
|
||||
MOV_INT => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let operand = get_32_le!(code, i, 2, u32);
|
||||
self.register_set.set_u32(target_register, operand, DmType::Int);
|
||||
i += 6;
|
||||
}
|
||||
MOV_LONG => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let operand = get_64_le!(code, i, 2, u64);
|
||||
self.register_set.set_u64(target_register, operand, DmType::Long);
|
||||
i += 10;
|
||||
}
|
||||
MOV_DOUBLE => { /* todo */ }
|
||||
MOV_REGISTER => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let source_register = code[i + 2] as usize;
|
||||
let (value, dm_type) = self.register_set.get(source_register);
|
||||
self.register_set.set_u64(target_register, value, dm_type);
|
||||
i += 3;
|
||||
}
|
||||
ALLOC => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let size = get_32_le!(code, i, 2, usize);
|
||||
let layout = Layout::from_size_align(size, 4).unwrap();
|
||||
let pointer = unsafe { alloc_zeroed(layout) };
|
||||
let dm_object = Box::new(DmObject {
|
||||
data: pointer,
|
||||
size,
|
||||
layout,
|
||||
object_type: todo!(),
|
||||
});
|
||||
let dm_object_pointer = Box::into_raw(dm_object) as u64;
|
||||
self.register_set.set_u64(target_register, dm_object_pointer as u64, DmType::Pointer);
|
||||
i += 6;
|
||||
}
|
||||
DEALLOC => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let (box_address, register_type) = self.register_set.get(target_register);
|
||||
if register_type != DmType::Pointer {
|
||||
panic!("Attempt to deallocate at the address stored in a register that is not a pointer.");
|
||||
}
|
||||
unsafe {
|
||||
let dm_object = Box::from_raw(box_address as *mut DmObject);
|
||||
dealloc(dm_object.data, dm_object.layout);
|
||||
}
|
||||
self.register_set.set_u64(target_register, 0, DmType::Unit);
|
||||
i += 2;
|
||||
}
|
||||
MOV_INT_TO => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let (box_address, register_type) = self.register_set.get(target_register);
|
||||
if register_type != DmType::Pointer {
|
||||
panic!("target_register {} is not a Pointer", target_register);
|
||||
}
|
||||
let offset = get_32_le!(code, i, 2, isize);
|
||||
let new_address = unsafe {
|
||||
let dm_object = Box::from_raw(box_address as *mut DmObject);
|
||||
let pointer = dm_object.data;
|
||||
pointer.offset(offset).write(code[i + 6]);
|
||||
pointer.offset(offset + 1).write(code[i + 7]);
|
||||
pointer.offset(offset + 2).write(code[i + 8]);
|
||||
pointer.offset(offset + 3).write(code[i + 9]);
|
||||
Box::into_raw(dm_object) as u64
|
||||
};
|
||||
self.register_set.set_u64(target_register, new_address, DmType::Pointer);
|
||||
i += 10;
|
||||
}
|
||||
PLATFORM_CALL => {
|
||||
i += 1;
|
||||
|
||||
let symbol_name_length = get_32_le!(code, i, 1, usize);
|
||||
i += 4;
|
||||
|
||||
let symbol_name_raw = code[i..(i + symbol_name_length)].to_vec();
|
||||
i += symbol_name_length;
|
||||
|
||||
let symbol_name = String::from_utf8(symbol_name_raw).unwrap();
|
||||
|
||||
let 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 platform_function_result = self.platform_functions.get(&symbol_name);
|
||||
if platform_function_result.is_none() {
|
||||
panic!("Unknown function {}", symbol_name);
|
||||
}
|
||||
let platform_function = platform_function_result.unwrap();
|
||||
|
||||
let mut args = Vec::new();
|
||||
let mut arg_types = Vec::new();
|
||||
for (value, dm_type) in self.register_set.iter() {
|
||||
args.push(value);
|
||||
arg_types.push(dm_type);
|
||||
}
|
||||
|
||||
match platform_function(PlatformCallFrame {
|
||||
name: symbol_name,
|
||||
args,
|
||||
arg_types,
|
||||
vm: self
|
||||
}) {
|
||||
Ok(result_opt) => {
|
||||
match result_opt {
|
||||
Some((result, result_type)) => {
|
||||
// todo: put in register
|
||||
},
|
||||
None => {
|
||||
// TODO: put Unit in register
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => panic!("{}", e)
|
||||
}
|
||||
}
|
||||
_ => panic!("Invalid code instruction"),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub struct DmObjectType {
|
||||
name: String,
|
||||
properties: HashMap<String, DmObjectProperty>,
|
||||
@ -56,83 +330,6 @@ pub struct DmObjectField {
|
||||
field_type: DmType,
|
||||
}
|
||||
|
||||
pub fn run(code: &Vec<u8>, registers: &mut Vec<u64>, register_types: &mut Vec<DmType>) {
|
||||
let mut i = 0;
|
||||
while i < code.len() {
|
||||
match code[i] {
|
||||
MOV_INT => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let operand = get_32_le!(code, i, 2, u32);
|
||||
registers[target_register] = operand as u64;
|
||||
register_types[target_register] = DmType::Int;
|
||||
i += 6;
|
||||
}
|
||||
MOV_LONG => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let operand = get_64_le!(code, i, 2, u64);
|
||||
registers[target_register] = operand;
|
||||
register_types[target_register] = DmType::Long;
|
||||
i += 10;
|
||||
}
|
||||
MOV_DOUBLE => { /* todo */ }
|
||||
MOV_REGISTER => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let source_register = code[i + 2] as usize;
|
||||
registers[target_register] = registers[source_register];
|
||||
register_types[target_register] = register_types[source_register].clone();
|
||||
i += 3;
|
||||
}
|
||||
ALLOC => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let size = get_32_le!(code, i, 2, usize);
|
||||
let layout = Layout::from_size_align(size, 4).unwrap();
|
||||
let pointer = unsafe { alloc_zeroed(layout) };
|
||||
let dm_object = Box::new(DmObject {
|
||||
data: pointer,
|
||||
size,
|
||||
layout,
|
||||
object_type: todo!(),
|
||||
});
|
||||
let dm_object_pointer = Box::into_raw(dm_object) as u64;
|
||||
registers[target_register] = dm_object_pointer;
|
||||
register_types[target_register] = DmType::Pointer;
|
||||
i += 6;
|
||||
}
|
||||
DEALLOC => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let box_address = registers[target_register];
|
||||
unsafe {
|
||||
let dm_object = Box::from_raw(box_address as *mut DmObject);
|
||||
dealloc(dm_object.data, dm_object.layout);
|
||||
}
|
||||
registers[target_register] = 0;
|
||||
register_types[target_register] = DmType::Int;
|
||||
i += 2;
|
||||
}
|
||||
MOV_INT_TO => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
if register_types[target_register] != DmType::Pointer {
|
||||
panic!("target_register {} is not a Pointer", target_register);
|
||||
}
|
||||
let offset = get_32_le!(code, i, 2, isize);
|
||||
let box_address = registers[target_register];
|
||||
let new_address = unsafe {
|
||||
let dm_object = Box::from_raw(box_address as *mut DmObject);
|
||||
let pointer = dm_object.data;
|
||||
pointer.offset(offset).write(code[i + 6]);
|
||||
pointer.offset(offset + 1).write(code[i + 7]);
|
||||
pointer.offset(offset + 2).write(code[i + 8]);
|
||||
pointer.offset(offset + 3).write(code[i + 9]);
|
||||
Box::into_raw(dm_object) as u64
|
||||
};
|
||||
registers[target_register] = new_address;
|
||||
i += 10;
|
||||
}
|
||||
_ => panic!("Invalid code instruction"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -24,6 +24,7 @@ pub enum DmConstant {
|
||||
pub struct DmFunction {
|
||||
pub name: String,
|
||||
pub byte_code: Vec<u8>,
|
||||
pub num_registers: usize,
|
||||
}
|
||||
|
||||
const CONST_SYMBOL: u8 = 0x01;
|
||||
|
@ -81,8 +81,12 @@ pub fn add_mov_int_to(code: &mut Vec<u8>, register: u8, offset: u32, operand: u3
|
||||
push_number!(code, operand);
|
||||
}
|
||||
|
||||
pub fn add_platform_call_to(code: &mut Vec<u8>, symbol_name: &String) {
|
||||
pub fn add_platform_call_to(code: &mut Vec<u8>, symbol_name: &String, arg_registers_length: u8, arg_registers: &Vec<u8>) {
|
||||
code.push(PLATFORM_CALL);
|
||||
push_number!(code, symbol_name.len());
|
||||
push_string!(code, symbol_name);
|
||||
push_number!(code, arg_registers_length);
|
||||
for &b in arg_registers {
|
||||
code.push(b);
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,9 @@
|
||||
use crate::vm::platform::std_lib::core::dm_print;
|
||||
use crate::vm::{DmVirtualMachine, PlatformFunction};
|
||||
use crate::vm::PlatformFunction;
|
||||
use std::collections::HashMap;
|
||||
|
||||
mod std_lib;
|
||||
|
||||
pub struct PlatformCallFrame {
|
||||
args: Vec<u64>,
|
||||
arg_types: Vec<crate::vm::types::DmType>,
|
||||
vm: DmVirtualMachine,
|
||||
}
|
||||
|
||||
pub fn init_platform_functions() -> HashMap<String, PlatformFunction> {
|
||||
let mut fns: HashMap<String, PlatformFunction> = HashMap::new();
|
||||
fns.insert(String::from("std::core::print"), dm_print);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::vm::platform::PlatformCallFrame;
|
||||
use crate::vm::types::DmType;
|
||||
use crate::vm::PlatformCallFrame;
|
||||
use crate::vm::DmObject;
|
||||
use DmType::*;
|
||||
|
||||
@ -7,7 +7,7 @@ pub struct DmString {
|
||||
data: String,
|
||||
}
|
||||
|
||||
pub fn dm_print(frame: &mut PlatformCallFrame) -> Result<Option<(u64, DmType)>, String> {
|
||||
pub fn dm_print(frame: PlatformCallFrame) -> Result<Option<(u64, DmType)>, String> {
|
||||
if frame.args.len() != 1 {
|
||||
return Err(String::from("std::core::print requires one argument."));
|
||||
}
|
||||
@ -28,10 +28,9 @@ pub fn dm_print(frame: &mut PlatformCallFrame) -> Result<Option<(u64, DmType)>,
|
||||
.methods
|
||||
.get(&String::from("to_string"))
|
||||
{
|
||||
let call_result =
|
||||
frame
|
||||
let call_result = frame
|
||||
.vm
|
||||
.call(to_string_method, vec![frame.args[0]], vec![Pointer]);
|
||||
.call(&to_string_method, [frame.args[0]], [frame.arg_types[0]]);
|
||||
if call_result.is_err() {
|
||||
return Err(call_result.unwrap_err());
|
||||
}
|
||||
@ -43,6 +42,12 @@ pub fn dm_print(frame: &mut PlatformCallFrame) -> Result<Option<(u64, DmType)>,
|
||||
print!("{}@{:?}", dm_object.object_type.name, dm_object.data);
|
||||
}
|
||||
},
|
||||
Unit => {
|
||||
print!("Unit")
|
||||
},
|
||||
Exception => {
|
||||
print!("Exception")
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
|
||||
pub enum DmType {
|
||||
Int,
|
||||
Long,
|
||||
Double,
|
||||
Pointer,
|
||||
Unit,
|
||||
Exception
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user