Start work on platform calls.

This commit is contained in:
Jesse Brault 2024-11-29 22:35:01 -06:00
parent 4fb7ada6b8
commit 438d0e7317
8 changed files with 161 additions and 38 deletions

View File

@ -1,23 +1,62 @@
mod module; mod module;
mod op_codes; mod op_codes;
mod util; mod util;
mod platform;
mod types;
use op_codes::*; use op_codes::*;
use platform::PlatformCallFrame;
use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::collections::HashMap;
use types::DmType;
use util::{get_32_le, get_64_le}; use util::{get_32_le, get_64_le};
use crate::vm::module::DmFunction;
pub type PlatformFunction = fn (&mut PlatformCallFrame) -> Result<Option<(u64, DmType)>, String>;
pub struct DmVirtualMachine { pub struct DmVirtualMachine {
registers: Vec<u64>, registers: Vec<u64>,
register_types: Vec<RegisterType>, register_types: Vec<DmType>,
platform_functions: HashMap<String, PlatformFunction>
} }
struct DmObject { impl DmVirtualMachine {
pointer: *mut u8, 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!()
}
}
pub struct DmObjectType {
name: String,
properties: HashMap<String, DmObjectProperty>,
fields: HashMap<String, DmObjectField>,
methods: HashMap<String, DmFunction>
}
pub struct DmObject {
object_type: Box<DmObjectType>,
data: *mut u8,
size: usize, size: usize,
layout: Layout, layout: Layout,
} }
pub fn run(code: &Vec<u8>, registers: &mut Vec<u64>, register_types: &mut Vec<RegisterType>) { pub struct DmObjectProperty {
name: String,
property_type: DmType,
}
pub struct DmObjectField {
name: String,
field_type: DmType,
}
pub fn run(code: &Vec<u8>, registers: &mut Vec<u64>, register_types: &mut Vec<DmType>) {
let mut i = 0; let mut i = 0;
while i < code.len() { while i < code.len() {
match code[i] { match code[i] {
@ -25,14 +64,14 @@ pub fn run(code: &Vec<u8>, registers: &mut Vec<u64>, register_types: &mut Vec<Re
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);
registers[target_register] = operand as u64; registers[target_register] = operand as u64;
register_types[target_register] = RegisterType::Int; register_types[target_register] = DmType::Int;
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);
registers[target_register] = operand; registers[target_register] = operand;
register_types[target_register] = RegisterType::Long; register_types[target_register] = DmType::Long;
i += 10; i += 10;
} }
MOV_DOUBLE => { /* todo */ } MOV_DOUBLE => { /* todo */ }
@ -49,13 +88,14 @@ pub fn run(code: &Vec<u8>, registers: &mut Vec<u64>, register_types: &mut Vec<Re
let layout = Layout::from_size_align(size, 4).unwrap(); let layout = Layout::from_size_align(size, 4).unwrap();
let pointer = unsafe { alloc_zeroed(layout) }; let pointer = unsafe { alloc_zeroed(layout) };
let dm_object = Box::new(DmObject { let dm_object = Box::new(DmObject {
pointer, data: pointer,
size, size,
layout, layout,
object_type: todo!()
}); });
let dm_object_pointer = Box::into_raw(dm_object) as u64; let dm_object_pointer = Box::into_raw(dm_object) as u64;
registers[target_register] = dm_object_pointer; registers[target_register] = dm_object_pointer;
register_types[target_register] = RegisterType::Pointer; register_types[target_register] = DmType::Pointer;
i += 6; i += 6;
} }
DEALLOC => { DEALLOC => {
@ -63,22 +103,22 @@ pub fn run(code: &Vec<u8>, registers: &mut Vec<u64>, register_types: &mut Vec<Re
let box_address = registers[target_register]; let box_address = registers[target_register];
unsafe { unsafe {
let dm_object = Box::from_raw(box_address as *mut DmObject); let dm_object = Box::from_raw(box_address as *mut DmObject);
dealloc(dm_object.pointer, dm_object.layout); dealloc(dm_object.data, dm_object.layout);
} }
registers[target_register] = 0; registers[target_register] = 0;
register_types[target_register] = RegisterType::Int; register_types[target_register] = DmType::Int;
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;
if register_types[target_register] != RegisterType::Pointer { if register_types[target_register] != DmType::Pointer {
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 offset = get_32_le!(code, i, 2, isize);
let box_address = registers[target_register]; let box_address = registers[target_register];
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(box_address as *mut DmObject);
let pointer = dm_object.pointer; let pointer = dm_object.data;
pointer.offset(offset).write(code[i + 6]); pointer.offset(offset).write(code[i + 6]);
pointer.offset(offset + 1).write(code[i + 7]); pointer.offset(offset + 1).write(code[i + 7]);
pointer.offset(offset + 2).write(code[i + 8]); pointer.offset(offset + 2).write(code[i + 8]);
@ -98,8 +138,8 @@ mod tests {
use super::*; use super::*;
use std::alloc::dealloc; use std::alloc::dealloc;
fn init_registers(n_registers: usize) -> (Vec<u64>, Vec<RegisterType>) { fn init_registers(n_registers: usize) -> (Vec<u64>, Vec<DmType>) {
(vec![0; n_registers], vec![RegisterType::Int; n_registers]) (vec![0; n_registers], vec![DmType::Int; n_registers])
} }
#[test] #[test]
@ -145,13 +185,13 @@ mod tests {
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 registers = vec![0; 16];
let mut register_types = vec![RegisterType::Int; 16]; let mut register_types = vec![DmType::Int; 16];
run(&code, &mut registers, &mut register_types); run(&code, &mut registers, &mut register_types);
let box_address = registers[0]; let box_address = registers[0];
unsafe { unsafe {
let dm_object = Box::from_raw(box_address as *mut DmObject); let dm_object = Box::from_raw(box_address as *mut DmObject);
assert_eq!(0xff, *dm_object.pointer); assert_eq!(0xff, *dm_object.data);
dealloc(dm_object.pointer, dm_object.layout); dealloc(dm_object.data, dm_object.layout);
} }
} }
@ -163,6 +203,6 @@ mod tests {
let (mut registers, mut register_types) = init_registers(1); let (mut registers, mut register_types) = init_registers(1);
run(&code, &mut registers, &mut register_types); run(&code, &mut registers, &mut register_types);
assert_eq!(0, registers[0]); assert_eq!(0, registers[0]);
assert_eq!(RegisterType::Int, register_types[0]); assert_eq!(DmType::Int, register_types[0]);
} }
} }

View File

@ -22,8 +22,8 @@ pub enum DmConstant {
} }
pub struct DmFunction { pub struct DmFunction {
name: String, pub name: String,
byte_code: Vec<u8>, pub byte_code: Vec<u8>,
} }
const CONST_SYMBOL: u8 = 0x01; const CONST_SYMBOL: u8 = 0x01;

View File

@ -1,3 +1,5 @@
use crate::push_bytes;
/// ## mov(register: u8, operand: u32) /// ## mov(register: u8, operand: u32)
/// - 0: opcode /// - 0: opcode
/// - 1: register /// - 1: register
@ -35,20 +37,24 @@ pub const MOV_LONG_TO: u8 = 0x08;
pub const MOV_DOUBLE_TO: u8 = 0x09; pub const MOV_DOUBLE_TO: u8 = 0x09;
pub const MOV_REGISTER_TO: u8 = 0x0a; pub const MOV_REGISTER_TO: u8 = 0x0a;
#[derive(PartialEq, Eq, Clone, Debug)] pub const PLATFORM_CALL: u8 = 0x10;
pub enum RegisterType {
Int, macro_rules! push_number {
Long, ( $dest: expr, $num: expr ) => {
Double, push_bytes!($dest, $num.to_le_bytes())
Pointer, }
}
macro_rules! push_string {
( $dest: expr, $s: expr ) => {
push_bytes!($dest, $s.bytes())
};
} }
pub fn add_mov_int(code: &mut Vec<u8>, register: u8, operand: u32) { pub fn add_mov_int(code: &mut Vec<u8>, register: u8, operand: u32) {
code.push(MOV_INT); code.push(MOV_INT);
code.push(register); code.push(register);
for b in operand.to_le_bytes() { push_number!(code, operand);
code.push(b);
}
} }
pub fn add_mov_register(code: &mut Vec<u8>, target_register: u8, source_register: u8) { pub fn add_mov_register(code: &mut Vec<u8>, target_register: u8, source_register: u8) {
@ -60,9 +66,7 @@ pub fn add_mov_register(code: &mut Vec<u8>, target_register: u8, source_register
pub fn add_alloc(code: &mut Vec<u8>, register: u8, size: u32) { pub fn add_alloc(code: &mut Vec<u8>, register: u8, size: u32) {
code.push(ALLOC); code.push(ALLOC);
code.push(register); code.push(register);
for b in size.to_le_bytes() { push_number!(code, size);
code.push(b);
}
} }
pub fn add_dealloc(code: &mut Vec<u8>, register: u8) { pub fn add_dealloc(code: &mut Vec<u8>, register: u8) {
@ -73,10 +77,12 @@ pub fn add_dealloc(code: &mut Vec<u8>, register: u8) {
pub fn add_mov_int_to(code: &mut Vec<u8>, register: u8, offset: u32, operand: u32) { pub fn add_mov_int_to(code: &mut Vec<u8>, register: u8, offset: u32, operand: u32) {
code.push(MOV_INT_TO); code.push(MOV_INT_TO);
code.push(register); code.push(register);
for b in offset.to_le_bytes() { push_number!(code, offset);
code.push(b); push_number!(code, operand);
}
for b in operand.to_le_bytes() {
code.push(b);
} }
pub fn add_platform_call_to(code: &mut Vec<u8>, symbol_name: &String) {
code.push(PLATFORM_CALL);
push_number!(code, symbol_name.len());
push_string!(code, symbol_name);
} }

17
src/vm/platform/mod.rs Normal file
View File

@ -0,0 +1,17 @@
use std::collections::HashMap;
use crate::vm::{DmVirtualMachine, PlatformFunction};
use crate::vm::platform::std_lib::core::dm_print;
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 m: HashMap<String, PlatformFunction> = HashMap::new();
m.insert(String::from("std::core::print"), dm_print);
m
}

View File

@ -0,0 +1,42 @@
use crate::vm::platform::PlatformCallFrame;
use crate::vm::types::DmType;
use crate::vm::DmObject;
use DmType::*;
pub struct DmString {
data: String
}
pub fn dm_print(frame: &mut PlatformCallFrame) -> Result<Option<(u64, DmType)>, String> {
if frame.args.len() != 1 {
return Err(String::from("std::core::print requires one argument."));
}
match frame.arg_types[0] {
Int => {
print!("{}", frame.args[0] as i32);
}
Long => {
print!("{}", frame.args[0] as i64);
}
Double => {
print!("{}", frame.args[0] as f64);
}
Pointer => unsafe {
let dm_object = Box::from_raw(frame.args[0] as *mut DmObject);
if let Some(&ref to_string_method) = dm_object.object_type.methods.get(&String::from("to_string")) {
let call_result = frame.vm.call(to_string_method, vec![frame.args[0]], vec![Pointer]);
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 {
print!("{}@{:?}", dm_object.object_type.name, dm_object.data);
}
}
}
Ok(None)
}

View File

@ -0,0 +1 @@
pub mod core;

7
src/vm/types.rs Normal file
View File

@ -0,0 +1,7 @@
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum DmType {
Int,
Long,
Double,
Pointer,
}

View File

@ -22,5 +22,15 @@ macro_rules! get_64_le {
}; };
} }
#[macro_export]
macro_rules! push_bytes {
( $dest: expr, $src: expr ) => {
for b in $src {
$dest.push(b);
}
};
}
pub use get_32_le; pub use get_32_le;
pub use get_64_le; pub use get_64_le;
pub use push_bytes;