All the work to print 42 via a platform call.

This commit is contained in:
Jesse Brault 2024-11-30 16:03:22 -06:00
parent a14eb550ce
commit 5732c4d197
4 changed files with 167 additions and 248 deletions

View File

@ -1,14 +1,11 @@
use std::process::exit;
use deimos::vm::DmVirtualMachine;
use deimos::vm::op_codes::{add_mov_int, add_platform_call_to}; use deimos::vm::op_codes::{add_mov_int, add_platform_call_to};
use deimos::vm::DmVirtualMachine;
fn main() { fn main() {
let mut code: Vec<u8> = Vec::new(); let mut code: Vec<u8> = Vec::new();
add_mov_int(&mut code, 0, 42); add_mov_int(&mut code, 0, 42);
add_platform_call_to(&mut code, &String::from("std::core::print"), 1, &vec![0u8]); add_platform_call_to(&mut code, &String::from("std::core::print"), 0, 1, &vec![0u8]);
let mut vm = DmVirtualMachine::new(); let mut vm = DmVirtualMachine::new();
if let Err(_) = vm.run(&mut code) { vm.run(&mut code);
eprintln!("There was an exception."); println!()
exit(1);
}
} }

View File

@ -12,194 +12,109 @@ use std::collections::HashMap;
use std::ops::Index; use std::ops::Index;
use types::DmType; use types::DmType;
use util::{get_32_le, get_64_le}; use util::{get_32_le, get_64_le};
use crate::vm::DmValue::{DmInt, DmLong, DmPointer, DmUnit};
pub type PlatformFunction = fn(PlatformCallFrame) -> Result<Option<(u64, DmType)>, String>; pub type PlatformFunction = fn(args: Vec<DmValue>, &mut DmVirtualMachine) -> DmValue;
enum CallFrame<'a> { #[derive(Debug, Clone, Copy, PartialEq)]
PlatformCall(PlatformCallFrame<'a>), pub enum DmValue {
DeimosCall(DeimosCallFrame<'a>) DmInt(i32),
DmLong(i64),
DmDouble(f64),
DmPointer(*mut DmObject),
DmUnit,
DmException(*mut DmObject)
} }
pub struct PlatformCallFrame<'a> { enum CallFrame {
PlatformCall(PlatformCallFrame),
DeimosCall(DeimosCallFrame)
}
pub struct PlatformCallFrame {
pub name: String, pub name: String,
pub args: Vec<u64>, pub args: Vec<u64>,
pub arg_types: Vec<DmType>, pub arg_types: Vec<DmType>,
pub vm: &'a mut DmVirtualMachine<'a>
} }
struct DeimosCallFrame<'a> { struct DeimosCallFrame {
return_address: usize, return_address: usize,
dm_function: &'a DmFunction
} }
struct RegisterSet { pub struct DmVirtualMachine {
size: usize,
registers: Vec<u64>,
register_types: Vec<DmType>,
}
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>, platform_functions: HashMap<String, PlatformFunction>,
ip: usize, ip: usize,
call_stack: Vec<CallFrame<'a>>, call_stack: Vec<CallFrame>,
register_set: RegisterSet, registers: Vec<DmValue>,
register_state_stack: Vec<RegisterSet>, register_state_stack: Vec<Vec<DmValue>>,
} }
impl DmVirtualMachine<'_> { impl DmVirtualMachine {
pub fn new<'a>() -> DmVirtualMachine<'a> { pub fn new() -> DmVirtualMachine {
DmVirtualMachine { DmVirtualMachine {
ip: 0, ip: 0,
register_set: RegisterSet::new(0), registers: Vec::new(),
platform_functions: init_platform_functions(), platform_functions: init_platform_functions(),
call_stack: Vec::new(), call_stack: Vec::new(),
register_state_stack: Vec::new(), register_state_stack: Vec::new(),
} }
} }
pub fn call<const ArgLen: usize>( pub fn call(
&mut self, &mut self,
dm_function: &DmFunction, dm_function: &DmFunction,
args: [u64; ArgLen], args: Vec<DmValue>,
arg_types: [DmType; ArgLen], ) -> DmValue {
) -> Result<(u64, DmType), String> {
// 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,
dm_function
})); }));
self.register_state_stack.push(self.register_set.clone()); self.register_state_stack.push(self.registers.clone());
// zero registers and make sure there are enough for dm_function // zero registers and make sure there are enough for dm_function
self.register_set.clear(); self.registers.clear();
self.register_set.ensure_capacity(dm_function.num_registers); self.registers.resize(args.len(), DmValue::DmUnit);
// push args // push args
for i in 0..args.len() { for i in 0..args.len() {
let arg = args[i]; self.registers.insert(i, args[i]);
let arg_type = arg_types[i];
self.register_set.set_u64(i, arg, arg_type);
} }
// run the byte code // run the byte code
let call_result = self.run(&dm_function.byte_code); self.run(&dm_function.byte_code);
// restore state // restore state
self.register_set = self.register_state_stack.pop().unwrap(); self.registers = self.register_state_stack.pop().unwrap();
if let CallFrame::DeimosCall(deimos_call_frame) = self.call_stack.pop().unwrap() { if let CallFrame::DeimosCall(deimos_call_frame) = self.call_stack.pop().unwrap() {
self.ip = deimos_call_frame.return_address; self.ip = deimos_call_frame.return_address;
} }
// return result // return result
if let Err(_) = call_result { self.registers.get(0).unwrap().clone()
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<(), ()> { pub fn run(&mut self, code: &Vec<u8>) {
let mut i = 0; let mut i = 0;
while i < code.len() { while i < code.len() {
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;
let operand = get_32_le!(code, i, 2, u32); let operand = get_32_le!(code, i, 2, u32);
self.register_set.set_u32(target_register, operand, DmType::Int); self.registers.insert(target_register, DmInt(operand as i32));
i += 6; i += 6;
} }
MOV_LONG => { MOV_LONG => {
let target_register = code[i + 1] as usize; let target_register = code[i + 1] as usize;
let operand = get_64_le!(code, i, 2, u64); let operand = get_64_le!(code, i, 2, u64);
self.register_set.set_u64(target_register, operand, DmType::Long); self.registers.insert(target_register, DmLong(operand as i64));
i += 10; i += 10;
} }
MOV_DOUBLE => { /* todo */ } MOV_DOUBLE => { /* todo */ }
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;
let (value, dm_type) = self.register_set.get(source_register); let source_value = self.registers.get(source_register).unwrap();
self.register_set.set_u64(target_register, value, dm_type); self.registers.insert(target_register, source_value.clone());
i += 3; i += 3;
} }
ALLOC => { ALLOC => {
@ -213,46 +128,49 @@ impl DmVirtualMachine<'_> {
layout, layout,
object_type: todo!(), object_type: todo!(),
}); });
let dm_object_pointer = Box::into_raw(dm_object) as u64; let dm_object_pointer = Box::into_raw(dm_object);
self.register_set.set_u64(target_register, dm_object_pointer as u64, DmType::Pointer); self.registers.insert(target_register, DmPointer(dm_object_pointer));
i += 6; i += 6;
} }
DEALLOC => { DEALLOC => {
let target_register = code[i + 1] as usize; let target_register = code[i + 1] as usize;
let (box_address, register_type) = self.register_set.get(target_register); let target_value = self.registers.get(target_register).unwrap();
if register_type != DmType::Pointer { match target_value {
panic!("Attempt to deallocate at the address stored in a register that is not a pointer."); DmPointer(ptr) => unsafe {
let dm_object = Box::from_raw(ptr.clone());
dealloc(dm_object.data, dm_object.layout);
}
_ => {
panic!("Attempt to deallocate at the address stored in a register that is not a pointer.");
}
} }
unsafe { self.registers.insert(target_register, DmUnit);
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; i += 2;
} }
MOV_INT_TO => { MOV_INT_TO => {
let target_register = code[i + 1] as usize; let target_register = code[i + 1] as usize;
let (box_address, register_type) = self.register_set.get(target_register); let target_value = self.registers.get(target_register).unwrap();
if register_type != DmType::Pointer { if let DmPointer(dm_object_ptr) = target_value {
let offset = get_32_le!(code, i, 2, isize);
let new_address = unsafe {
let dm_object = Box::from_raw(dm_object_ptr.clone());
let data_ptr = dm_object.data;
data_ptr.offset(offset).write(code[i + 6]);
data_ptr.offset(offset + 1).write(code[i + 7]);
data_ptr.offset(offset + 2).write(code[i + 8]);
data_ptr.offset(offset + 3).write(code[i + 9]);
Box::into_raw(dm_object)
};
self.registers.insert(target_register, DmPointer(new_address));
i += 10;
} else {
panic!("target_register {} is not a Pointer", target_register); 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 => { PLATFORM_CALL => {
i += 1; i += 1;
let symbol_name_length = get_32_le!(code, i, 1, usize); let symbol_name_length = get_32_le!(code, i, 0, usize);
i += 4; i += 4;
let symbol_name_raw = code[i..(i + symbol_name_length)].to_vec(); let symbol_name_raw = code[i..(i + symbol_name_length)].to_vec();
@ -260,48 +178,33 @@ impl DmVirtualMachine<'_> {
let symbol_name = String::from_utf8(symbol_name_raw).unwrap(); let symbol_name = String::from_utf8(symbol_name_raw).unwrap();
let return_register = code[i + 1] as usize;
i += 1;
let arg_registers_length = code[i] as usize; let arg_registers_length = code[i] as usize;
i += 1; i += 1;
let arg_registers = code[i..(i + arg_registers_length)].to_vec(); let arg_registers = code[i..(i + arg_registers_length)].to_vec();
i += arg_registers_length; i += arg_registers_length;
let mut args = Vec::new();
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); let platform_function_result = self.platform_functions.get(&symbol_name);
if platform_function_result.is_none() { if platform_function_result.is_none() {
panic!("Unknown function {}", symbol_name); panic!("Unknown platform function {}", symbol_name);
} }
let platform_function = platform_function_result.unwrap(); let platform_function = platform_function_result.unwrap();
let mut args = Vec::new(); let call_result = platform_function(args, self);
let mut arg_types = Vec::new(); self.registers.insert(return_register, call_result);
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"), _ => panic!("Invalid code instruction"),
} }
} }
Ok(())
} }
} }
@ -331,75 +234,81 @@ pub struct DmObjectField {
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod dvm_run_tests {
use super::*; use super::*;
use std::alloc::dealloc; use std::alloc::dealloc;
fn init_registers(n_registers: usize) -> (Vec<u64>, Vec<DmType>) { macro_rules! assert_register {
(vec![0; n_registers], vec![DmType::Int; n_registers]) ( $expected: expr, $register: expr ) => {
assert_eq!($expected, $register.unwrap().clone());
};
} }
#[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 registers, mut register_types) = init_registers(1); let mut vm = DmVirtualMachine::new();
run(&code, &mut registers, &mut register_types); vm.run(&code);
assert_eq!(1, registers[0]); assert_register!(DmInt(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 registers, mut register_types) = init_registers(1); let mut vm = DmVirtualMachine::new();
run(&code, &mut registers, &mut register_types); vm.run(&code);
assert_eq!(0xffff, registers[0]); assert_register!(DmInt(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, 0xffff_ffff); add_mov_int(&mut code, 0, 0x0fff_ffff);
let (mut registers, mut register_types) = init_registers(1); let mut vm = DmVirtualMachine::new();
run(&code, &mut registers, &mut register_types); vm.run(&code);
assert_eq!(0xffff_ffff, registers[0]); assert_register!(DmInt(0x0fff_ffff), vm.registers.get(0));
} }
#[test] #[test]
fn move_register() { fn move_register() {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 1, 1);
add_mov_register(&mut code, 0, 1); add_mov_register(&mut code, 0, 1);
let (mut registers, mut register_types) = init_registers(2); let mut vm = DmVirtualMachine::new();
registers[1] = 1; vm.registers.resize(2, DmUnit);
run(&code, &mut registers, &mut register_types); vm.run(&code);
assert_eq!(registers[0], 1); assert_register!(DmInt(1), vm.registers.get(0));
} }
#[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);
add_mov_int_to(&mut code, 0, 0, 0xff); add_mov_int_to(&mut code, 0, 0, 0xff);
let mut registers = vec![0; 16]; let mut vm = DmVirtualMachine::new();
let mut register_types = vec![DmType::Int; 16]; vm.run(&code);
run(&code, &mut registers, &mut register_types); let box_address = vm.registers.get(0).unwrap().clone();
let box_address = registers[0]; match box_address {
unsafe { DmPointer(ptr) => unsafe {
let dm_object = Box::from_raw(box_address as *mut DmObject); let dm_object = Box::from_raw(ptr);
assert_eq!(0xff, *dm_object.data); assert_eq!(0xff, *dm_object.data);
dealloc(dm_object.data, dm_object.layout); dealloc(dm_object.data, dm_object.layout);
},
_ => panic!("Target register is not a pointer"),
} }
} }
#[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);
add_dealloc(&mut code, 0); add_dealloc(&mut code, 0);
let (mut registers, mut register_types) = init_registers(1); let mut vm = DmVirtualMachine::new();
run(&code, &mut registers, &mut register_types); vm.run(&code);
assert_eq!(0, registers[0]); assert_register!(DmUnit, vm.registers.get(0));
assert_eq!(DmType::Int, register_types[0]);
} }
} }

View File

@ -81,10 +81,11 @@ 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, arg_registers_length: u8, arg_registers: &Vec<u8>) { pub fn add_platform_call_to(code: &mut Vec<u8>, symbol_name: &String, 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()); push_number!(code, symbol_name.len() as u32);
push_string!(code, symbol_name); push_string!(code, symbol_name);
push_number!(code, return_register);
push_number!(code, arg_registers_length); push_number!(code, arg_registers_length);
for &b in arg_registers { for &b in arg_registers {
code.push(b); code.push(b);

View File

@ -1,53 +1,65 @@
use crate::vm::types::DmType; use crate::vm::types::DmType;
use crate::vm::PlatformCallFrame; use crate::vm::DmValue::*;
use crate::vm::DmObject; use crate::vm::{DmObject, DmValue, DmVirtualMachine};
use DmType::*; use DmType::*;
use crate::vm::module::DmFunction;
pub struct DmString { fn get_method<'a>(ptr: *mut DmObject, name: String) -> Option<&'a DmFunction> {
data: String, unsafe {
(*ptr).object_type.methods.get(&name)
}
} }
pub fn dm_print(frame: PlatformCallFrame) -> Result<Option<(u64, DmType)>, String> { fn get_rust_string_from_dm_object(ptr: *mut DmObject) -> String {
if frame.args.len() != 1 { unsafe {
return Err(String::from("std::core::print requires one argument.")); let dm_object = Box::from_raw(ptr);
format!("{}@{:?}", dm_object.object_type.name, dm_object.data)
} }
match frame.arg_types[0] { }
Int => {
print!("{}", frame.args[0] as i32); fn get_rust_string_from_dm_string(ptr: *mut DmObject) -> String {
unsafe {
let dm_string = Box::from_raw(ptr);
todo!()
}
}
pub fn dm_print(args: Vec<DmValue>, vm: &mut DmVirtualMachine) -> DmValue {
if args.len() != 1 {
return DmException(todo!("make an Exception object."))
}
match args[0] {
DmInt(i) => {
print!("{}", i);
} }
Long => { DmLong(l) => {
print!("{}", frame.args[0] as i64); print!("{}", l);
} }
Double => { DmDouble(d) => {
print!("{}", frame.args[0] as f64); print!("{}", d);
} }
Pointer => unsafe { DmPointer(ptr) => {
let dm_object = Box::from_raw(frame.args[0] as *mut DmObject); if let Some(to_string) = get_method(ptr, String::from("to_string")) {
if let Some(&ref to_string_method) = dm_object let call_result = vm.call(&to_string, vec![args[0]]);
.object_type match call_result {
.methods DmPointer(dm_string_ptr) => {
.get(&String::from("to_string")) let string = get_rust_string_from_dm_string(dm_string_ptr);
{ print!("{}", string);
let call_result = frame }
.vm _ => {
.call(&to_string_method, [frame.args[0]], [frame.arg_types[0]]); // TODO: vm throw or return exception?
if call_result.is_err() { }
return Err(call_result.unwrap_err());
} }
let (dm_string_address, _) = call_result?;
// TODO: check that it's actually a DmString
let dm_string = Box::from_raw(dm_string_address as *mut DmString);
print!("{}", dm_string.data);
} else { } else {
print!("{}@{:?}", dm_object.object_type.name, dm_object.data); print!("{}", get_rust_string_from_dm_object(ptr));
} }
}, },
Unit => { DmUnit => {
print!("Unit") print!("Unit")
}, },
Exception => { DmException(e) => {
print!("Exception") print!("Exception")
} }
} }
Ok(None) DmUnit
} }