Start work on platform calls.
This commit is contained in:
parent
4fb7ada6b8
commit
438d0e7317
@ -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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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
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_32_le;
|
||||||
pub use get_64_le;
|
pub use get_64_le;
|
||||||
|
pub use push_bytes;
|
||||||
|
Loading…
Reference in New Issue
Block a user