Start work on platform calls.
This commit is contained in:
parent
4fb7ada6b8
commit
438d0e7317
@ -1,23 +1,62 @@
|
||||
mod module;
|
||||
mod op_codes;
|
||||
mod util;
|
||||
mod platform;
|
||||
mod types;
|
||||
|
||||
use op_codes::*;
|
||||
use platform::PlatformCallFrame;
|
||||
use std::alloc::{alloc_zeroed, dealloc, Layout};
|
||||
use std::collections::HashMap;
|
||||
use types::DmType;
|
||||
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 {
|
||||
registers: Vec<u64>,
|
||||
register_types: Vec<RegisterType>,
|
||||
register_types: Vec<DmType>,
|
||||
platform_functions: HashMap<String, PlatformFunction>
|
||||
}
|
||||
|
||||
struct DmObject {
|
||||
pointer: *mut u8,
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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;
|
||||
while i < code.len() {
|
||||
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 operand = get_32_le!(code, i, 2, u32);
|
||||
registers[target_register] = operand as u64;
|
||||
register_types[target_register] = RegisterType::Int;
|
||||
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] = RegisterType::Long;
|
||||
register_types[target_register] = DmType::Long;
|
||||
i += 10;
|
||||
}
|
||||
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 pointer = unsafe { alloc_zeroed(layout) };
|
||||
let dm_object = Box::new(DmObject {
|
||||
pointer,
|
||||
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] = RegisterType::Pointer;
|
||||
register_types[target_register] = DmType::Pointer;
|
||||
i += 6;
|
||||
}
|
||||
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];
|
||||
unsafe {
|
||||
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;
|
||||
register_types[target_register] = RegisterType::Int;
|
||||
register_types[target_register] = DmType::Int;
|
||||
i += 2;
|
||||
}
|
||||
MOV_INT_TO => {
|
||||
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);
|
||||
}
|
||||
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.pointer;
|
||||
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]);
|
||||
@ -98,8 +138,8 @@ mod tests {
|
||||
use super::*;
|
||||
use std::alloc::dealloc;
|
||||
|
||||
fn init_registers(n_registers: usize) -> (Vec<u64>, Vec<RegisterType>) {
|
||||
(vec![0; n_registers], vec![RegisterType::Int; n_registers])
|
||||
fn init_registers(n_registers: usize) -> (Vec<u64>, Vec<DmType>) {
|
||||
(vec![0; n_registers], vec![DmType::Int; n_registers])
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -145,13 +185,13 @@ mod tests {
|
||||
add_alloc(&mut code, 0, 4);
|
||||
add_mov_int_to(&mut code, 0, 0, 0xff);
|
||||
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);
|
||||
let box_address = registers[0];
|
||||
unsafe {
|
||||
let dm_object = Box::from_raw(box_address as *mut DmObject);
|
||||
assert_eq!(0xff, *dm_object.pointer);
|
||||
dealloc(dm_object.pointer, dm_object.layout);
|
||||
assert_eq!(0xff, *dm_object.data);
|
||||
dealloc(dm_object.data, dm_object.layout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,6 +203,6 @@ mod tests {
|
||||
let (mut registers, mut register_types) = init_registers(1);
|
||||
run(&code, &mut registers, &mut register_types);
|
||||
assert_eq!(0, registers[0]);
|
||||
assert_eq!(RegisterType::Int, register_types[0]);
|
||||
assert_eq!(DmType::Int, register_types[0]);
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ pub enum DmConstant {
|
||||
}
|
||||
|
||||
pub struct DmFunction {
|
||||
name: String,
|
||||
byte_code: Vec<u8>,
|
||||
pub name: String,
|
||||
pub byte_code: Vec<u8>,
|
||||
}
|
||||
|
||||
const CONST_SYMBOL: u8 = 0x01;
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::push_bytes;
|
||||
|
||||
/// ## mov(register: u8, operand: u32)
|
||||
/// - 0: opcode
|
||||
/// - 1: register
|
||||
@ -35,20 +37,24 @@ pub const MOV_LONG_TO: u8 = 0x08;
|
||||
pub const MOV_DOUBLE_TO: u8 = 0x09;
|
||||
pub const MOV_REGISTER_TO: u8 = 0x0a;
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub enum RegisterType {
|
||||
Int,
|
||||
Long,
|
||||
Double,
|
||||
Pointer,
|
||||
pub const PLATFORM_CALL: u8 = 0x10;
|
||||
|
||||
macro_rules! push_number {
|
||||
( $dest: expr, $num: expr ) => {
|
||||
push_bytes!($dest, $num.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
code.push(MOV_INT);
|
||||
code.push(register);
|
||||
for b in operand.to_le_bytes() {
|
||||
code.push(b);
|
||||
}
|
||||
push_number!(code, operand);
|
||||
}
|
||||
|
||||
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) {
|
||||
code.push(ALLOC);
|
||||
code.push(register);
|
||||
for b in size.to_le_bytes() {
|
||||
code.push(b);
|
||||
}
|
||||
push_number!(code, size);
|
||||
}
|
||||
|
||||
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) {
|
||||
code.push(MOV_INT_TO);
|
||||
code.push(register);
|
||||
for b in offset.to_le_bytes() {
|
||||
code.push(b);
|
||||
}
|
||||
for b in operand.to_le_bytes() {
|
||||
code.push(b);
|
||||
}
|
||||
push_number!(code, offset);
|
||||
push_number!(code, operand);
|
||||
}
|
||||
|
||||
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
17
src/vm/platform/mod.rs
Normal 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
|
||||
}
|
42
src/vm/platform/std_lib/core.rs
Normal file
42
src/vm/platform/std_lib/core.rs
Normal 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)
|
||||
}
|
||||
|
1
src/vm/platform/std_lib/mod.rs
Normal file
1
src/vm/platform/std_lib/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod core;
|
7
src/vm/types.rs
Normal file
7
src/vm/types.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub enum DmType {
|
||||
Int,
|
||||
Long,
|
||||
Double,
|
||||
Pointer,
|
||||
}
|
@ -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_64_le;
|
||||
pub use push_bytes;
|
||||
|
Loading…
Reference in New Issue
Block a user