All the work to print 42 via a platform call.
This commit is contained in:
parent
a14eb550ce
commit
5732c4d197
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
309
src/vm/mod.rs
309
src/vm/mod.rs
@ -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());
|
||||||
unsafe {
|
|
||||||
let dm_object = Box::from_raw(box_address as *mut DmObject);
|
|
||||||
dealloc(dm_object.data, dm_object.layout);
|
dealloc(dm_object.data, dm_object.layout);
|
||||||
}
|
}
|
||||||
self.register_set.set_u64(target_register, 0, DmType::Unit);
|
_ => {
|
||||||
|
panic!("Attempt to deallocate at the address stored in a register that is not a pointer.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.registers.insert(target_register, DmUnit);
|
||||||
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 {
|
||||||
panic!("target_register {} is not a Pointer", target_register);
|
|
||||||
}
|
|
||||||
let offset = get_32_le!(code, i, 2, isize);
|
let offset = get_32_le!(code, i, 2, isize);
|
||||||
let new_address = unsafe {
|
let new_address = unsafe {
|
||||||
let dm_object = Box::from_raw(box_address as *mut DmObject);
|
let dm_object = Box::from_raw(dm_object_ptr.clone());
|
||||||
let pointer = dm_object.data;
|
let data_ptr = dm_object.data;
|
||||||
pointer.offset(offset).write(code[i + 6]);
|
data_ptr.offset(offset).write(code[i + 6]);
|
||||||
pointer.offset(offset + 1).write(code[i + 7]);
|
data_ptr.offset(offset + 1).write(code[i + 7]);
|
||||||
pointer.offset(offset + 2).write(code[i + 8]);
|
data_ptr.offset(offset + 2).write(code[i + 8]);
|
||||||
pointer.offset(offset + 3).write(code[i + 9]);
|
data_ptr.offset(offset + 3).write(code[i + 9]);
|
||||||
Box::into_raw(dm_object) as u64
|
Box::into_raw(dm_object)
|
||||||
};
|
};
|
||||||
self.register_set.set_u64(target_register, new_address, DmType::Pointer);
|
self.registers.insert(target_register, DmPointer(new_address));
|
||||||
i += 10;
|
i += 10;
|
||||||
|
} else {
|
||||||
|
panic!("target_register {} is not a Pointer", target_register);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
Long => {
|
|
||||||
print!("{}", frame.args[0] as i64);
|
fn get_rust_string_from_dm_string(ptr: *mut DmObject) -> String {
|
||||||
|
unsafe {
|
||||||
|
let dm_string = Box::from_raw(ptr);
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
Double => {
|
|
||||||
print!("{}", frame.args[0] as f64);
|
|
||||||
}
|
}
|
||||||
Pointer => unsafe {
|
|
||||||
let dm_object = Box::from_raw(frame.args[0] as *mut DmObject);
|
pub fn dm_print(args: Vec<DmValue>, vm: &mut DmVirtualMachine) -> DmValue {
|
||||||
if let Some(&ref to_string_method) = dm_object
|
if args.len() != 1 {
|
||||||
.object_type
|
return DmException(todo!("make an Exception object."))
|
||||||
.methods
|
}
|
||||||
.get(&String::from("to_string"))
|
match args[0] {
|
||||||
{
|
DmInt(i) => {
|
||||||
let call_result = frame
|
print!("{}", i);
|
||||||
.vm
|
}
|
||||||
.call(&to_string_method, [frame.args[0]], [frame.arg_types[0]]);
|
DmLong(l) => {
|
||||||
if call_result.is_err() {
|
print!("{}", l);
|
||||||
return Err(call_result.unwrap_err());
|
}
|
||||||
|
DmDouble(d) => {
|
||||||
|
print!("{}", d);
|
||||||
|
}
|
||||||
|
DmPointer(ptr) => {
|
||||||
|
if let Some(to_string) = get_method(ptr, String::from("to_string")) {
|
||||||
|
let call_result = vm.call(&to_string, vec![args[0]]);
|
||||||
|
match call_result {
|
||||||
|
DmPointer(dm_string_ptr) => {
|
||||||
|
let string = get_rust_string_from_dm_string(dm_string_ptr);
|
||||||
|
print!("{}", string);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// TODO: vm throw or return exception?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user