Massive work just to try to start printing a String.
This commit is contained in:
parent
97376bad72
commit
6190beaed2
@ -1,5 +1,8 @@
|
|||||||
ns std::core
|
ns std::core
|
||||||
|
|
||||||
|
use std::unsafe::Pointer
|
||||||
|
use std::unsafe::mem::{alloc, pointer_of)
|
||||||
|
|
||||||
pub int Array<T> : Monad + Default + Empty {
|
pub int Array<T> : Monad + Default + Empty {
|
||||||
const default = array::empty<Self>
|
const default = array::empty<Self>
|
||||||
const empty = array::empty<Self>
|
const empty = array::empty<Self>
|
||||||
@ -7,12 +10,42 @@ pub int Array<T> : Monad + Default + Empty {
|
|||||||
length: Int
|
length: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ArrayImpl<T> : Array<T> {
|
||||||
|
|
||||||
|
fld pointer: Pointer<T>
|
||||||
|
fld length: Int
|
||||||
|
|
||||||
|
pub unsafe ctor(length: Int) {
|
||||||
|
self.pointer = alloc(length * T::size())
|
||||||
|
self.length = length
|
||||||
|
}
|
||||||
|
|
||||||
|
pub ctor(pointer: Pointer<T>, length: Int) {
|
||||||
|
self.pointer = pointer
|
||||||
|
self.length = length
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn set(index: Int, item: Pointer<T>) {
|
||||||
|
pointer.offset(index * T::size()).write(item.read())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub mod array {
|
pub mod array {
|
||||||
|
|
||||||
// Usage:
|
// Usage:
|
||||||
// let int_array = array::of(1, 2, 3)
|
// let int_array = array::of(1, 2, 3)
|
||||||
// assert_eq(3, int_array.length)
|
// assert_eq(3, int_array.length)
|
||||||
pub extern fn of<T>(ts: ...T): Array<T>
|
pub fn of<T>(ts: ...T): Array<T> {
|
||||||
|
unsafe {
|
||||||
|
let array = ArrayImpl<T>(ts.length)
|
||||||
|
for (i, t) in ts.enumerate() {
|
||||||
|
let t_pointer = pointer_of(t)
|
||||||
|
array.set(i, t_pointer)
|
||||||
|
}
|
||||||
|
array
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub extern fn of_length<T>(length: Int, init_value: T): Array<T>
|
pub extern fn of_length<T>(length: Int, init_value: T): Array<T>
|
||||||
|
|
||||||
|
18
dm_lib/std/unsafe/mem.dm
Normal file
18
dm_lib/std/unsafe/mem.dm
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
ns std::unsafe
|
||||||
|
|
||||||
|
pub int Pointer<T> {}
|
||||||
|
|
||||||
|
impl PointerImpl<T> {
|
||||||
|
|
||||||
|
fld raw_address: Long
|
||||||
|
fld size: Long
|
||||||
|
|
||||||
|
decl ctor(size: Long)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod mem {
|
||||||
|
|
||||||
|
pub fn <T> alloc(size: Long): Pointer<T> = PointerImpl(size)
|
||||||
|
|
||||||
|
}
|
@ -1,22 +1,233 @@
|
|||||||
use deimos::vm::op_codes::{add_mov_int, add_platform_call_to};
|
use deimos::vm::dm_type::DmType;
|
||||||
|
use deimos::vm::lib::{DmConstant, DmLib};
|
||||||
|
use deimos::vm::object_type::{DmField, DmFn, DmImplementation, DmInterface, DmMethod};
|
||||||
|
use deimos::vm::op_codes::{
|
||||||
|
add_alloc, add_alloc_raw_from, add_invoke_fn, add_invoke_method, add_mov_const,
|
||||||
|
add_mov_register_to, add_mov_size_of, add_multiply, add_platform_call, add_ret,
|
||||||
|
add_ret_register,
|
||||||
|
};
|
||||||
use deimos::vm::DmVirtualMachine;
|
use deimos::vm::DmVirtualMachine;
|
||||||
use deimos::vm::dvm_value::DvmValue;
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// TODO:
|
// Goal:
|
||||||
// - write a single module with a main()
|
// - write a single lib with a main()
|
||||||
// - call the main fn
|
// - call the main fn
|
||||||
|
// fn main() { println "Hello, World!" }
|
||||||
let mut code: Vec<u8> = Vec::new();
|
|
||||||
add_mov_int(&mut code, 0, 0x2a); // 42
|
// std/unsafe/mem lib
|
||||||
add_platform_call_to(
|
let mut unsafe_mem_lib = DmLib::new("std/unsafe/mem");
|
||||||
&mut code,
|
|
||||||
&String::from("std::core::println"),
|
// std::unsafe::Pointer
|
||||||
0,
|
let unsafe_pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer");
|
||||||
1,
|
let unsafe_pointer_rc = Rc::new(unsafe_pointer_int);
|
||||||
&vec![0u8],
|
|
||||||
|
// std::unsafe::PointerImpl : Pointer
|
||||||
|
let mut unsafe_pointer_impl = DmImplementation::new(
|
||||||
|
"std::unsafe:PointerImpl",
|
||||||
|
"PointerImpl",
|
||||||
|
Some(unsafe_pointer_rc.clone()),
|
||||||
);
|
);
|
||||||
let mut vm = DmVirtualMachine::new(Vec::new());
|
|
||||||
vm.run_raw(&mut code);
|
let raw_address_field = DmField::new("raw_address", DmType::Long, 0);
|
||||||
vm.call_by_fqn("default::main", vec![DvmValue::Unit; 0]); // will throw
|
let size_field = DmField::new("size", DmType::Long, 8);
|
||||||
|
|
||||||
|
// std::unsafe::Pointer::_ctor_0(
|
||||||
|
// r0: self
|
||||||
|
// r1: size Long
|
||||||
|
// )
|
||||||
|
// r2: raw_address Long
|
||||||
|
let mut unsafe_pointer_ctor_0_bytecode: Vec<u8> = Vec::new();
|
||||||
|
add_alloc_raw_from(&mut unsafe_pointer_ctor_0_bytecode, 2, 1);
|
||||||
|
add_mov_register_to(
|
||||||
|
&mut unsafe_pointer_ctor_0_bytecode,
|
||||||
|
0,
|
||||||
|
raw_address_field.data_offset() as u32,
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
add_mov_register_to(
|
||||||
|
&mut unsafe_pointer_ctor_0_bytecode,
|
||||||
|
0,
|
||||||
|
size_field.data_offset() as u32,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let unsafe_pointer_init_fn = DmFn::new(
|
||||||
|
"std::unsafe::PointerImpl::_ctor_0",
|
||||||
|
"_ctor_0",
|
||||||
|
unsafe_pointer_ctor_0_bytecode,
|
||||||
|
3,
|
||||||
|
);
|
||||||
|
|
||||||
|
let unsafe_pointer_init_method = DmMethod::new(unsafe_pointer_init_fn, None);
|
||||||
|
|
||||||
|
unsafe_pointer_impl.fields.push(raw_address_field);
|
||||||
|
unsafe_pointer_impl.fields.push(size_field);
|
||||||
|
unsafe_pointer_impl
|
||||||
|
.methods
|
||||||
|
.push(Rc::new(unsafe_pointer_init_method));
|
||||||
|
|
||||||
|
let unsafe_pointer_impl_rc = Rc::new(unsafe_pointer_impl);
|
||||||
|
|
||||||
|
unsafe_mem_lib.interfaces.push(unsafe_pointer_rc.clone());
|
||||||
|
unsafe_mem_lib
|
||||||
|
.implementations
|
||||||
|
.push(unsafe_pointer_impl_rc.clone());
|
||||||
|
|
||||||
|
// std::unsafe::alloc(
|
||||||
|
// r0: size Long
|
||||||
|
// )
|
||||||
|
// r0: size Long
|
||||||
|
// r1: Pointer object
|
||||||
|
// @return r1
|
||||||
|
let mut alloc_fn_byte_code: Vec<u8> = Vec::new();
|
||||||
|
add_alloc(
|
||||||
|
&mut alloc_fn_byte_code,
|
||||||
|
1,
|
||||||
|
unsafe_pointer_impl_rc.size_in_bytes() as u32,
|
||||||
|
"std::unsafe::PointerImpl",
|
||||||
|
);
|
||||||
|
add_invoke_method(
|
||||||
|
&mut alloc_fn_byte_code,
|
||||||
|
"std::unsafe::Pointer::_ctor_0",
|
||||||
|
&[1u8, 0u8],
|
||||||
|
);
|
||||||
|
add_ret_register(&mut alloc_fn_byte_code, 1);
|
||||||
|
|
||||||
|
let alloc_fn = DmFn {
|
||||||
|
fqn: "std::unsafe::mem::alloc".to_string(),
|
||||||
|
short_name: "alloc".to_string(),
|
||||||
|
byte_code: alloc_fn_byte_code,
|
||||||
|
number_used_registers: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe_mem_lib.functions.push(Rc::new(alloc_fn));
|
||||||
|
|
||||||
|
// std::core::Array
|
||||||
|
let core_array_int = DmInterface::new("std::core::Array", "Array");
|
||||||
|
let core_array_int_rc = Rc::new(core_array_int);
|
||||||
|
|
||||||
|
// std::core::ArrayImpl
|
||||||
|
let mut core_array_impl = DmImplementation::new(
|
||||||
|
"std::core::ArrayImpl",
|
||||||
|
"ArrayImpl",
|
||||||
|
Some(core_array_int_rc.clone()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let array_impl_pointer_fld = DmField::new("pointer", DmType::Pointer, 0);
|
||||||
|
let array_impl_length_fld = DmField::new("length", DmType::Int, 8);
|
||||||
|
|
||||||
|
// std::core::Array::_ctor_0(
|
||||||
|
// r0: self
|
||||||
|
// r1: TypeRef element_type
|
||||||
|
// r2: Int length
|
||||||
|
// )
|
||||||
|
// r3: r1::size()
|
||||||
|
// r4: r3 * r1
|
||||||
|
// r5: Pointer allocated pointer
|
||||||
|
let mut array_impl_ctor_0_bytecode: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
add_mov_size_of(&mut array_impl_ctor_0_bytecode, 3, 1);
|
||||||
|
add_multiply(&mut array_impl_ctor_0_bytecode, 4, 3, 1);
|
||||||
|
add_invoke_fn(
|
||||||
|
&mut array_impl_ctor_0_bytecode,
|
||||||
|
"std::unsafe::mem::alloc",
|
||||||
|
5,
|
||||||
|
&[4],
|
||||||
|
);
|
||||||
|
add_mov_register_to(
|
||||||
|
&mut array_impl_ctor_0_bytecode,
|
||||||
|
0,
|
||||||
|
array_impl_pointer_fld.data_offset() as u32,
|
||||||
|
5,
|
||||||
|
);
|
||||||
|
add_mov_register_to(
|
||||||
|
&mut array_impl_ctor_0_bytecode,
|
||||||
|
0,
|
||||||
|
array_impl_length_fld.data_offset() as u32,
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
|
||||||
|
let array_impl_ctor_0_fn = DmFn::new(
|
||||||
|
"std::core::ArrayImpl::_ctor_0",
|
||||||
|
"_ctor_0",
|
||||||
|
array_impl_ctor_0_bytecode,
|
||||||
|
6,
|
||||||
|
);
|
||||||
|
let array_impl_ctor_0_method = DmMethod::new(array_impl_ctor_0_fn, None);
|
||||||
|
core_array_impl
|
||||||
|
.methods
|
||||||
|
.push(Rc::new(array_impl_ctor_0_method));
|
||||||
|
|
||||||
|
// std::core::String
|
||||||
|
|
||||||
|
let mut core_string_lib = DmLib::new("std/core/string");
|
||||||
|
let mut core_string_impl = DmImplementation::new("std::core::String", "String", None);
|
||||||
|
|
||||||
|
let bytes_field = DmField::new("bytes", DmType::Pointer, 0);
|
||||||
|
|
||||||
|
// std::core::String::_ctor_0(
|
||||||
|
// r0: self
|
||||||
|
// r1: DvmPointer to Array<Byte>
|
||||||
|
// )
|
||||||
|
let mut core_string_ctor_0_bytecode: Vec<u8> = Vec::new();
|
||||||
|
add_mov_register_to(
|
||||||
|
&mut core_string_ctor_0_bytecode,
|
||||||
|
0,
|
||||||
|
bytes_field.data_offset() as u32,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let core_string_ctor_0_fn = DmFn {
|
||||||
|
fqn: "std::core::String::_ctor_0".to_string(),
|
||||||
|
short_name: "_ctor_0".to_string(),
|
||||||
|
byte_code: core_string_ctor_0_bytecode,
|
||||||
|
number_used_registers: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
let core_string_ctor_0_method = DmMethod::new(core_string_ctor_0_fn, None);
|
||||||
|
|
||||||
|
core_string_impl.fields.push(bytes_field);
|
||||||
|
core_string_impl.methods.push(Rc::new(core_string_ctor_0_method));
|
||||||
|
let core_string_impl_size = core_string_impl.size_in_bytes();
|
||||||
|
|
||||||
|
core_string_lib
|
||||||
|
.implementations
|
||||||
|
.push(Rc::new(core_string_impl));
|
||||||
|
|
||||||
|
let mut greeting_lib = DmLib::new("greeting");
|
||||||
|
greeting_lib
|
||||||
|
.constants
|
||||||
|
.push(DmConstant::String("Hello, World!".to_string()));
|
||||||
|
|
||||||
|
let mut main_byte_code = Vec::new();
|
||||||
|
|
||||||
|
// 1. Move constant: r0 receives DvmValue::Pointer to Array<Byte>
|
||||||
|
// 2. Allocate for std::core::String into r1
|
||||||
|
// 3. Call String::_ctor_0(r0) -> r2
|
||||||
|
// 4. Platform call std::core::println(r1) -> r3
|
||||||
|
add_alloc(
|
||||||
|
&mut main_byte_code,
|
||||||
|
0,
|
||||||
|
core_string_impl_size as u32,
|
||||||
|
"std::core::String",
|
||||||
|
);
|
||||||
|
add_mov_const(&mut main_byte_code, 1, "greeting", 0);
|
||||||
|
add_invoke_method(&mut main_byte_code, "std::core::String::_init_0", &[0, 1]);
|
||||||
|
add_platform_call(&mut main_byte_code, "std::core::println", 0, 1, &vec![0u8]);
|
||||||
|
|
||||||
|
let main_dm_fn = DmFn {
|
||||||
|
fqn: "default::main".to_string(),
|
||||||
|
short_name: "main".to_string(),
|
||||||
|
byte_code: main_byte_code,
|
||||||
|
number_used_registers: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
greeting_lib.functions.push(Rc::new(main_dm_fn));
|
||||||
|
|
||||||
|
let mut vm = DmVirtualMachine::new(vec![greeting_lib, core_string_lib]);
|
||||||
|
let main_fn = vm
|
||||||
|
.get_fn_by_fqn("default::main")
|
||||||
|
.expect("Could not find function: default::main");
|
||||||
|
vm.call_fn(&main_fn, Vec::new());
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,24 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
use crate::vm::object_type::DmObjectType;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum DmType {
|
pub enum DmType {
|
||||||
Primitive(DmPrimitiveType),
|
|
||||||
Object(Rc<DmObjectType>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub enum DmPrimitiveType {
|
|
||||||
Byte,
|
Byte,
|
||||||
Int,
|
Int,
|
||||||
Long,
|
Long,
|
||||||
Double,
|
Double,
|
||||||
Boolean,
|
Boolean,
|
||||||
Pointer(Rc<DmType>),
|
Pointer,
|
||||||
ByteArray(usize),
|
|
||||||
IntArray(usize),
|
|
||||||
LongArray(usize),
|
|
||||||
DoubleArray(usize),
|
|
||||||
BooleanArray(usize),
|
|
||||||
PointerArray(usize, Rc<DmType>),
|
|
||||||
Unit,
|
Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DmPrimitiveType {
|
impl DmType {
|
||||||
pub fn size_in_bytes(&self) -> usize {
|
pub fn size_in_bytes(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
DmPrimitiveType::Byte => size_of::<u8>(),
|
DmType::Byte => size_of::<u8>(),
|
||||||
DmPrimitiveType::Int => size_of::<i32>(),
|
DmType::Int => size_of::<i32>(),
|
||||||
DmPrimitiveType::Long => size_of::<i64>(),
|
DmType::Long => size_of::<i64>(),
|
||||||
DmPrimitiveType::Double => size_of::<f64>(),
|
DmType::Double => size_of::<f64>(),
|
||||||
DmPrimitiveType::Boolean => size_of::<bool>(),
|
DmType::Boolean => size_of::<bool>(),
|
||||||
DmPrimitiveType::Pointer(_) => size_of::<usize>(),
|
DmType::Pointer => size_of::<usize>(),
|
||||||
DmPrimitiveType::ByteArray(length) => *length * size_of::<u8>(),
|
DmType::Unit => todo!("Need to determine size of Unit... is it dependent on the size of the thing which is Unit?")
|
||||||
DmPrimitiveType::IntArray(length) => *length * size_of::<i32>(),
|
|
||||||
DmPrimitiveType::LongArray(length) => *length * size_of::<i64>(),
|
|
||||||
DmPrimitiveType::DoubleArray(length) => *length * size_of::<f64>(),
|
|
||||||
DmPrimitiveType::BooleanArray(length) => *length * size_of::<bool>(),
|
|
||||||
DmPrimitiveType::PointerArray(length, _) => *length * size_of::<usize>(),
|
|
||||||
DmPrimitiveType::Unit => todo!("Need to determine size of Unit... is it dependent on the size of the thing which is Unit?")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
use crate::vm::mem::DmAllocObject;
|
use crate::vm::mem::DmAllocObject;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum DvmValue {
|
pub enum DvmValue {
|
||||||
@ -9,11 +9,5 @@ pub enum DvmValue {
|
|||||||
Double(f64),
|
Double(f64),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Pointer(Rc<DmAllocObject>),
|
Pointer(Rc<DmAllocObject>),
|
||||||
ByteArray(Vec<u8>),
|
|
||||||
IntArray(Vec<i32>),
|
|
||||||
LongArray(Vec<i64>),
|
|
||||||
DoubleArray(Vec<f64>),
|
|
||||||
BooleanArray(Vec<bool>),
|
|
||||||
PointerArray(Vec<Rc<DmAllocObject>>),
|
|
||||||
Unit,
|
Unit,
|
||||||
}
|
}
|
||||||
|
@ -1,89 +1,13 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
use crate::get_32_le;
|
use crate::get_32_le;
|
||||||
use crate::vm::object_type::{DmFn, DmImplementation, DmInterface};
|
use crate::vm::lib::DmLib;
|
||||||
|
use crate::vm::lib::magic::{CONST_SYMBOL, DEIMOS_MAGIC_NUMBER, FUNCTION_SYMBOL};
|
||||||
|
use crate::vm::lib::symbol::LibSymbol;
|
||||||
|
|
||||||
pub const DEIMOS_MAGIC_NUMBER: u64 = 0x00_00_64_65_69_6d_6f_73; // ascii 'deimos'
|
pub fn load_module(bytes: &[u8]) -> Result<DmLib, String> {
|
||||||
pub const DEIMOS_MAGIC_STRING: [u8; 6] = [0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73]; // ascii 'deimos'
|
|
||||||
|
|
||||||
pub const COMPILER_VERSION_STRING: &str = "0.1.0";
|
|
||||||
|
|
||||||
pub struct DmModule {
|
|
||||||
pub compiler_version: String,
|
|
||||||
pub fqn: String,
|
|
||||||
pub short_name: String,
|
|
||||||
pub constants: Vec<DmConstant>,
|
|
||||||
pub interfaces: Vec<Rc<DmInterface>>,
|
|
||||||
pub implementations: Vec<Rc<DmImplementation>>,
|
|
||||||
pub functions: Vec<Rc<DmFn>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum DmConstant {
|
|
||||||
Int(i32),
|
|
||||||
Long(i64),
|
|
||||||
Double(f64),
|
|
||||||
String(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
const CONST_SYMBOL: u8 = 0x01;
|
|
||||||
const FUNCTION_SYMBOL: u8 = 0x02;
|
|
||||||
|
|
||||||
enum SymbolType {
|
|
||||||
Constant,
|
|
||||||
Function,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DmSymbol {
|
|
||||||
name: String,
|
|
||||||
symbol_type: SymbolType,
|
|
||||||
address: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! push_byte_array {
|
|
||||||
( $dest: expr, $arr: expr ) => {
|
|
||||||
for b in $arr {
|
|
||||||
$dest.push(b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! push_number_le {
|
|
||||||
( $dest: expr, $num: expr ) => {
|
|
||||||
for b in $num.to_le_bytes() {
|
|
||||||
$dest.push(b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! push_string {
|
|
||||||
( $dest: expr, $s: expr ) => {
|
|
||||||
for b in $s.len().to_le_bytes() {
|
|
||||||
$dest.push(b);
|
|
||||||
}
|
|
||||||
for b in $s.bytes() {
|
|
||||||
$dest.push(b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_module(module: DmModule) -> Vec<u8> {
|
|
||||||
// Push magic number
|
|
||||||
let mut result: Vec<u8> = Vec::new();
|
|
||||||
push_byte_array!(result, DEIMOS_MAGIC_STRING);
|
|
||||||
|
|
||||||
// Push version string
|
|
||||||
push_string!(result, module.compiler_version);
|
|
||||||
|
|
||||||
// Push module name length, little endian
|
|
||||||
push_string!(result, module.fqn);
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> {
|
|
||||||
let mut ip: usize = 0;
|
let mut ip: usize = 0;
|
||||||
// Check for magic number at bytes 0..5
|
// Check for magic number at bytes 0..5
|
||||||
if !check_deimos(&bytes) {
|
if !check_deimos(&bytes) {
|
||||||
return Err(String::from("Not a valid Deimos module."));
|
return Err(String::from("Not a valid Deimos lib."));
|
||||||
}
|
}
|
||||||
ip = 6;
|
ip = 6;
|
||||||
|
|
||||||
@ -103,13 +27,13 @@ pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> {
|
|||||||
// Check version string. We'll use this in the future to not load modules compiled later than
|
// Check version string. We'll use this in the future to not load modules compiled later than
|
||||||
// current version.
|
// current version.
|
||||||
if version_string != "0.1.0" {
|
if version_string != "0.1.0" {
|
||||||
return Err(String::from("Invalid Deimos module version."));
|
return Err(String::from("Invalid Deimos lib version."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: extract module name
|
// TODO: extract lib name
|
||||||
|
|
||||||
// Holder for Symbols we will extract from the symbol table bytes
|
// Holder for Symbols we will extract from the symbol table bytes
|
||||||
let mut symbols: Vec<DmSymbol> = Vec::new();
|
let mut symbols: Vec<LibSymbol> = Vec::new();
|
||||||
|
|
||||||
// Get the symbol table length and calculate how far we need to read
|
// Get the symbol table length and calculate how far we need to read
|
||||||
let symbol_table_length = get_32_le!(bytes, 10 + version_string_length, 0, usize);
|
let symbol_table_length = get_32_le!(bytes, 10 + version_string_length, 0, usize);
|
||||||
@ -118,7 +42,7 @@ pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> {
|
|||||||
// For each "row" in the symbol table,
|
// For each "row" in the symbol table,
|
||||||
// 1. Get the type
|
// 1. Get the type
|
||||||
// 2. Obtain the name's length and then get the name in utf8
|
// 2. Obtain the name's length and then get the name in utf8
|
||||||
// 3. Grab the address to the actual symbol in the module bytes
|
// 3. Grab the address to the actual symbol in the lib bytes
|
||||||
while ip < symbol_table_end {
|
while ip < symbol_table_end {
|
||||||
let type_byte = bytes[ip];
|
let type_byte = bytes[ip];
|
||||||
ip += 1;
|
ip += 1;
|
||||||
@ -129,16 +53,12 @@ pub fn load_module(bytes: &[u8]) -> Result<DmModule, String> {
|
|||||||
ip += name_string_length;
|
ip += name_string_length;
|
||||||
let address = get_32_le!(bytes, ip, 0, u32);
|
let address = get_32_le!(bytes, ip, 0, u32);
|
||||||
ip += 4;
|
ip += 4;
|
||||||
let symbol_type = match type_byte {
|
let lib_symbol = match type_byte {
|
||||||
CONST_SYMBOL => SymbolType::Constant,
|
CONST_SYMBOL => LibSymbol::Constant(name, address),
|
||||||
FUNCTION_SYMBOL => SymbolType::Function,
|
FUNCTION_SYMBOL => LibSymbol::Function(name, address),
|
||||||
_ => return Err(String::from("Invalid Deimos symbol type.")),
|
_ => return Err(String::from("Invalid Deimos symbol type.")),
|
||||||
};
|
};
|
||||||
symbols.push(DmSymbol {
|
symbols.push(lib_symbol);
|
||||||
name,
|
|
||||||
address,
|
|
||||||
symbol_type,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
@ -163,7 +83,7 @@ fn read_as_u64(bytes: &[u8]) -> u64 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod read_as_u64_tests {
|
mod read_as_u64_tests {
|
||||||
use crate::vm::module::{read_as_u64, DEIMOS_MAGIC_NUMBER};
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_6_bytes() {
|
fn read_6_bytes() {
|
7
src/vm/lib/magic.rs
Normal file
7
src/vm/lib/magic.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
pub const DEIMOS_MAGIC_NUMBER: u64 = 0x00_00_64_65_69_6d_6f_73; // ascii 'deimos'
|
||||||
|
pub const DEIMOS_MAGIC_STRING: [u8; 6] = [0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73]; // ascii 'deimos'
|
||||||
|
|
||||||
|
pub const COMPILER_VERSION_STRING: &str = "0.1.0";
|
||||||
|
|
||||||
|
pub const CONST_SYMBOL: u8 = 0x01;
|
||||||
|
pub const FUNCTION_SYMBOL: u8 = 0x02;
|
31
src/vm/lib/mod.rs
Normal file
31
src/vm/lib/mod.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
mod load;
|
||||||
|
mod magic;
|
||||||
|
mod symbol;
|
||||||
|
mod write;
|
||||||
|
|
||||||
|
use crate::vm::object_type::{DmFn, DmImplementation, DmInterface};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct DmLib {
|
||||||
|
pub name: String,
|
||||||
|
pub constants: Vec<DmConstant>,
|
||||||
|
pub interfaces: Vec<Rc<DmInterface>>,
|
||||||
|
pub implementations: Vec<Rc<DmImplementation>>,
|
||||||
|
pub functions: Vec<Rc<DmFn>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DmLib {
|
||||||
|
pub fn new(name: &str) -> DmLib {
|
||||||
|
DmLib {
|
||||||
|
name: name.to_string(),
|
||||||
|
constants: Vec::new(),
|
||||||
|
interfaces: Vec::new(),
|
||||||
|
implementations: Vec::new(),
|
||||||
|
functions: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum DmConstant {
|
||||||
|
String(String),
|
||||||
|
}
|
4
src/vm/lib/symbol.rs
Normal file
4
src/vm/lib/symbol.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub enum LibSymbol {
|
||||||
|
Constant(String, u32),
|
||||||
|
Function(String, u32),
|
||||||
|
}
|
40
src/vm/lib/write.rs
Normal file
40
src/vm/lib/write.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use crate::vm::lib::DmLib;
|
||||||
|
use crate::vm::lib::magic::{COMPILER_VERSION_STRING, DEIMOS_MAGIC_STRING};
|
||||||
|
|
||||||
|
macro_rules! push_byte_array {
|
||||||
|
( $dest: expr, $arr: expr ) => {
|
||||||
|
for b in $arr {
|
||||||
|
$dest.push(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! push_number_le {
|
||||||
|
( $dest: expr, $num: expr ) => {
|
||||||
|
for b in $num.to_le_bytes() {
|
||||||
|
$dest.push(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! push_string {
|
||||||
|
( $dest: expr, $s: expr ) => {
|
||||||
|
for b in $s.len().to_le_bytes() {
|
||||||
|
$dest.push(b);
|
||||||
|
}
|
||||||
|
for b in $s.bytes() {
|
||||||
|
$dest.push(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_module(module: DmLib) -> Vec<u8> {
|
||||||
|
// Push magic number
|
||||||
|
let mut result: Vec<u8> = Vec::new();
|
||||||
|
push_byte_array!(result, DEIMOS_MAGIC_STRING);
|
||||||
|
|
||||||
|
// Push version string
|
||||||
|
push_string!(result, COMPILER_VERSION_STRING);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
use crate::vm::dm_type::DmPrimitiveType;
|
use crate::vm::dm_type::DmType;
|
||||||
use crate::vm::dvm_value::DvmValue;
|
use crate::vm::dvm_value::DvmValue;
|
||||||
use crate::vm::object_type::DmImplementation;
|
use crate::vm::object_type::{DmField, DmImplementation};
|
||||||
use crate::vm::object_type::DmProperty;
|
|
||||||
use std::alloc::Layout;
|
use std::alloc::Layout;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -13,48 +12,30 @@ pub struct DmAllocObject {
|
|||||||
pub implementation: Rc<DmImplementation>,
|
pub implementation: Rc<DmImplementation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn get_property_value(
|
pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -> DvmValue {
|
||||||
dm_property: &DmProperty,
|
let data_size = dm_field.dm_type().size_in_bytes();
|
||||||
self_object: &DmAllocObject,
|
|
||||||
) -> DvmValue {
|
|
||||||
let data_size = dm_property.primitive_type.size_in_bytes();
|
|
||||||
let mut raw_data: Vec<u8> = Vec::with_capacity(data_size);
|
let mut raw_data: Vec<u8> = Vec::with_capacity(data_size);
|
||||||
for i in dm_property.data_offset..(dm_property.data_offset + data_size) {
|
for i in dm_field.data_offset()..(dm_field.data_offset() + data_size) {
|
||||||
raw_data.push(self_object.data.offset(i as isize).read());
|
raw_data.push(self_object.data.offset(i as isize).read());
|
||||||
}
|
}
|
||||||
match dm_property.primitive_type.as_ref() {
|
match dm_field.dm_type() {
|
||||||
DmPrimitiveType::Byte => DvmValue::Byte(raw_data[0]),
|
DmType::Byte => DvmValue::Byte(raw_data[0]),
|
||||||
DmPrimitiveType::Int => DvmValue::Int(i32::from_ne_bytes(
|
DmType::Int => DvmValue::Int(i32::from_ne_bytes(
|
||||||
raw_data[0..data_size].try_into().unwrap(),
|
raw_data[0..data_size].try_into().unwrap(),
|
||||||
)),
|
)),
|
||||||
DmPrimitiveType::Long => DvmValue::Long(i64::from_ne_bytes(
|
DmType::Long => DvmValue::Long(i64::from_ne_bytes(
|
||||||
raw_data[0..data_size].try_into().unwrap(),
|
raw_data[0..data_size].try_into().unwrap(),
|
||||||
)),
|
)),
|
||||||
DmPrimitiveType::Double => DvmValue::Double(f64::from_ne_bytes(
|
DmType::Double => DvmValue::Double(f64::from_ne_bytes(
|
||||||
raw_data[0..data_size].try_into().unwrap(),
|
raw_data[0..data_size].try_into().unwrap(),
|
||||||
)),
|
)),
|
||||||
DmPrimitiveType::Boolean => DvmValue::Boolean(raw_data[0] == 1),
|
DmType::Boolean => DvmValue::Boolean(raw_data[0] == 1),
|
||||||
DmPrimitiveType::Pointer(_) => {
|
DmType::Pointer => {
|
||||||
// read the pointer's (address) value
|
// read the pointer's (address) value
|
||||||
let address = usize::from_ne_bytes(raw_data[0..data_size].try_into().unwrap());
|
let address = usize::from_ne_bytes(raw_data[0..data_size].try_into().unwrap());
|
||||||
DvmValue::Pointer(Rc::from_raw(address as *const DmAllocObject))
|
DvmValue::Pointer(Rc::from_raw(address as *const DmAllocObject))
|
||||||
}
|
}
|
||||||
DmPrimitiveType::ByteArray(_) => DvmValue::ByteArray(raw_data),
|
DmType::Unit => DvmValue::Unit,
|
||||||
DmPrimitiveType::IntArray(length) => DvmValue::IntArray(read_i32_array(&raw_data, *length)),
|
|
||||||
DmPrimitiveType::LongArray(length) => {
|
|
||||||
DvmValue::LongArray(read_i64_array(&raw_data, *length))
|
|
||||||
}
|
|
||||||
DmPrimitiveType::DoubleArray(length) => {
|
|
||||||
DvmValue::DoubleArray(read_f64_array(&raw_data, *length))
|
|
||||||
}
|
|
||||||
DmPrimitiveType::BooleanArray(length) => DvmValue::BooleanArray(read_bool_array(&raw_data)),
|
|
||||||
DmPrimitiveType::PointerArray(length, _) => DvmValue::PointerArray(
|
|
||||||
read_usize_array(&raw_data, *length)
|
|
||||||
.iter()
|
|
||||||
.map(|raw_usize| Rc::from_raw(*raw_usize as *const DmAllocObject))
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
DmPrimitiveType::Unit => DvmValue::Unit,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
226
src/vm/mod.rs
226
src/vm/mod.rs
@ -1,17 +1,19 @@
|
|||||||
pub mod dm_type;
|
pub mod dm_type;
|
||||||
pub mod dvm_value;
|
pub mod dvm_value;
|
||||||
mod mem;
|
pub mod lib;
|
||||||
pub mod module;
|
pub mod mem;
|
||||||
mod object_type;
|
pub mod object_type;
|
||||||
pub mod op_codes;
|
pub mod op_codes;
|
||||||
pub mod platform;
|
pub mod platform;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
use crate::vm::dvm_value::DvmValue;
|
use crate::vm::dvm_value::DvmValue;
|
||||||
use crate::vm::module::DmModule;
|
use crate::vm::lib::{DmConstant, DmLib};
|
||||||
|
use crate::vm::mem::{get_field_value, DmAllocObject};
|
||||||
use crate::vm::object_type::DmFn;
|
use crate::vm::object_type::DmFn;
|
||||||
use crate::vm::platform::init_platform_functions;
|
use crate::vm::platform::init_platform_functions;
|
||||||
use op_codes::*;
|
use op_codes::*;
|
||||||
|
use std::alloc::{alloc, Layout};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use util::{get_32_le, get_64_le};
|
use util::{get_32_le, get_64_le};
|
||||||
@ -33,7 +35,7 @@ struct DeimosCallFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct DmVirtualMachine {
|
pub struct DmVirtualMachine {
|
||||||
modules: Vec<DmModule>,
|
libs: Vec<DmLib>,
|
||||||
functions: HashMap<String, Rc<DmFn>>,
|
functions: HashMap<String, Rc<DmFn>>,
|
||||||
platform_functions: HashMap<String, PlatformFunction>,
|
platform_functions: HashMap<String, PlatformFunction>,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
@ -42,35 +44,51 @@ pub struct DmVirtualMachine {
|
|||||||
register_state_stack: Vec<Vec<DvmValue>>,
|
register_state_stack: Vec<Vec<DvmValue>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_functions(modules: &Vec<DmModule>) -> HashMap<String, Rc<DmFn>> {
|
fn load_functions(destination: &mut HashMap<String, Rc<DmFn>>, libs: &Vec<DmLib>) {
|
||||||
let mut functions: HashMap<String, Rc<DmFn>> = HashMap::new();
|
for module in libs {
|
||||||
for module in modules {
|
for lib_fn in &module.functions {
|
||||||
for module_fn in &module.functions {
|
destination.insert(lib_fn.fqn.clone(), lib_fn.clone());
|
||||||
functions.insert(module_fn.fqn.clone(), module_fn.clone());
|
}
|
||||||
|
for interface_function in module
|
||||||
|
.interfaces
|
||||||
|
.iter()
|
||||||
|
.flat_map(|interface| interface.get_functions())
|
||||||
|
{
|
||||||
|
destination.insert(interface_function.fqn.clone(), interface_function.clone());
|
||||||
|
}
|
||||||
|
for implementation_function in module
|
||||||
|
.implementations
|
||||||
|
.iter()
|
||||||
|
.flat_map(|implementation| &implementation.functions)
|
||||||
|
{
|
||||||
|
destination.insert(
|
||||||
|
implementation_function.fqn.clone(),
|
||||||
|
implementation_function.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for interface in &module.interfaces {}
|
|
||||||
}
|
}
|
||||||
functions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DmVirtualMachine {
|
impl DmVirtualMachine {
|
||||||
pub fn new(modules: Vec<DmModule>) -> DmVirtualMachine {
|
pub fn new(libs: Vec<DmLib>) -> DmVirtualMachine {
|
||||||
DmVirtualMachine {
|
let mut vm = DmVirtualMachine {
|
||||||
modules,
|
libs: libs,
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
platform_functions: init_platform_functions(),
|
platform_functions: init_platform_functions(),
|
||||||
ip: 0,
|
ip: 0,
|
||||||
registers: Vec::new(),
|
registers: Vec::new(),
|
||||||
call_stack: Vec::new(),
|
call_stack: Vec::new(),
|
||||||
register_state_stack: Vec::new(),
|
register_state_stack: Vec::new(),
|
||||||
}
|
};
|
||||||
|
load_functions(&mut vm.functions, &vm.libs);
|
||||||
|
vm
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_by_fqn(&mut self, fn_fqn: &str, args: Vec<DvmValue>) -> DvmValue {
|
pub fn get_fn_by_fqn(&self, fqn: &str) -> Option<Rc<DmFn>> {
|
||||||
todo!()
|
self.functions.get(fqn).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_fn(&mut self, dm_function: &DmFn, args: Vec<DvmValue>) -> DvmValue {
|
pub fn call_fn(&mut self, dm_function: &DmFn, args: Vec<DvmValue>) -> Option<DvmValue> {
|
||||||
// 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,
|
||||||
@ -79,7 +97,9 @@ impl DmVirtualMachine {
|
|||||||
|
|
||||||
// zero registers and make sure there are enough for dm_function
|
// zero registers and make sure there are enough for dm_function
|
||||||
self.registers.clear();
|
self.registers.clear();
|
||||||
self.registers.resize(args.len(), DvmValue::Unit);
|
if self.registers.len() < args.len() {
|
||||||
|
self.registers.resize(args.len(), DvmValue::Unit);
|
||||||
|
}
|
||||||
|
|
||||||
// push args
|
// push args
|
||||||
for i in 0..args.len() {
|
for i in 0..args.len() {
|
||||||
@ -96,12 +116,14 @@ impl DmVirtualMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return result
|
// return result
|
||||||
self.registers.get(0).unwrap().clone()
|
self.registers.get(0).map(|x| x.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_raw(&mut self, code: &Vec<u8>) {
|
pub fn run_raw(&mut self, code: &Vec<u8>) {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < code.len() {
|
while i < code.len() {
|
||||||
|
let op_code = code[i];
|
||||||
|
println!("op_code: {:#04x}", op_code);
|
||||||
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;
|
||||||
@ -117,7 +139,9 @@ impl DmVirtualMachine {
|
|||||||
.insert(target_register, DvmValue::Long(operand as i64));
|
.insert(target_register, DvmValue::Long(operand as i64));
|
||||||
i += 10;
|
i += 10;
|
||||||
}
|
}
|
||||||
MOV_DOUBLE => { /* todo */ }
|
MOV_DOUBLE => {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
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;
|
||||||
@ -126,7 +150,46 @@ impl DmVirtualMachine {
|
|||||||
i += 3;
|
i += 3;
|
||||||
}
|
}
|
||||||
ALLOC => {
|
ALLOC => {
|
||||||
todo!()
|
i += 1;
|
||||||
|
let target_register = code[i] as usize;
|
||||||
|
i += 1;
|
||||||
|
let alloc_size = get_32_le!(code, i, 0, usize);
|
||||||
|
i += 4;
|
||||||
|
let raw_implementation_name_length = get_32_le!(code, i, 0, usize);
|
||||||
|
i += 4;
|
||||||
|
let raw_implementation_name_bytes =
|
||||||
|
code[i..(i + raw_implementation_name_length)].to_vec();
|
||||||
|
i += raw_implementation_name_length;
|
||||||
|
let implementation_name =
|
||||||
|
String::from_utf8(raw_implementation_name_bytes).unwrap();
|
||||||
|
|
||||||
|
let implementation = self
|
||||||
|
.libs
|
||||||
|
.iter()
|
||||||
|
.find_map(|lib| {
|
||||||
|
lib.implementations
|
||||||
|
.iter()
|
||||||
|
.find(|implementation| implementation.fqn == implementation_name)
|
||||||
|
})
|
||||||
|
.expect(&format!(
|
||||||
|
"Implementation not found: {}",
|
||||||
|
implementation_name
|
||||||
|
));
|
||||||
|
|
||||||
|
let layout = Layout::from_size_align(alloc_size, 1).unwrap();
|
||||||
|
let raw_data_ptr;
|
||||||
|
unsafe {
|
||||||
|
raw_data_ptr = alloc(layout);
|
||||||
|
}
|
||||||
|
let dm_alloc_object = DmAllocObject {
|
||||||
|
data: raw_data_ptr,
|
||||||
|
layout,
|
||||||
|
size: alloc_size,
|
||||||
|
implementation: implementation.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let dvm_value = DvmValue::Pointer(Rc::new(dm_alloc_object));
|
||||||
|
self.registers.insert(target_register, dvm_value);
|
||||||
}
|
}
|
||||||
DEALLOC => {
|
DEALLOC => {
|
||||||
todo!()
|
todo!()
|
||||||
@ -134,6 +197,79 @@ impl DmVirtualMachine {
|
|||||||
MOV_INT_TO => {
|
MOV_INT_TO => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
MOV_REGISTER_TO => {
|
||||||
|
i += 1;
|
||||||
|
let target_register = code[i] as usize;
|
||||||
|
i += 1;
|
||||||
|
let offset = get_32_le!(code, i, 0, isize);
|
||||||
|
i += 4;
|
||||||
|
let source_register = code[i] as usize;
|
||||||
|
i += 1;
|
||||||
|
|
||||||
|
let target_value = self.registers.get(target_register).unwrap();
|
||||||
|
let target_pointer = match target_value {
|
||||||
|
DvmValue::Pointer(alloc_object) => alloc_object.data,
|
||||||
|
_ => panic!("Expected a DvmValue::Pointer, but got: {:?}", target_value),
|
||||||
|
};
|
||||||
|
|
||||||
|
let source_value = self.registers.get(source_register).unwrap();
|
||||||
|
match source_value {
|
||||||
|
DvmValue::Pointer(source_alloc_object) => unsafe {
|
||||||
|
let source_pointer = Rc::into_raw(source_alloc_object.clone());
|
||||||
|
for (j, b) in (source_pointer as usize).to_le_bytes().iter().enumerate()
|
||||||
|
{
|
||||||
|
target_pointer.offset(offset + j as isize).write(*b);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => panic!("Currently unsupported source value: {:?}", source_value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MOV_CONST => {
|
||||||
|
i += 1;
|
||||||
|
let target_register = code[i] as usize;
|
||||||
|
i += 1;
|
||||||
|
let lib_name_length = get_32_le!(code, i, 0, usize);
|
||||||
|
i += 4;
|
||||||
|
let lib_name_raw = code[i..(i + lib_name_length)].to_vec();
|
||||||
|
i += lib_name_length;
|
||||||
|
let const_id = get_32_le!(code, i, 0, usize);
|
||||||
|
i += 4;
|
||||||
|
|
||||||
|
let lib_name = String::from_utf8(lib_name_raw).unwrap();
|
||||||
|
|
||||||
|
if let Some(lib) = self.libs.iter().find(|&lib| lib.name == lib_name) {
|
||||||
|
let constant = &lib.constants[const_id];
|
||||||
|
match constant {
|
||||||
|
DmConstant::String(s) => {
|
||||||
|
let alloc_fn = self.get_fn_by_fqn("std::unsafe::mem::alloc")
|
||||||
|
.expect("Could not find std::unsafe::mem::alloc");
|
||||||
|
let alloc_size_arg = DvmValue::Long(s.len() as i64);
|
||||||
|
let alloc_return_value = self.call_fn(&alloc_fn, vec![alloc_size_arg]).unwrap();
|
||||||
|
let DvmValue::Pointer(pointer_object) = alloc_return_value else {
|
||||||
|
panic!("Expected std::unsafe::mem::alloc to return DvmValue::Pointer, but got: {:?}", alloc_return_value);
|
||||||
|
};
|
||||||
|
let raw_address_field = pointer_object.implementation.get_field("raw_address", &pointer_object)
|
||||||
|
.expect("Could not get PointerImpl.raw_address field.");
|
||||||
|
unsafe {
|
||||||
|
let raw_address_value = get_field_value(&raw_address_field, &pointer_object);
|
||||||
|
let DvmValue::Long(raw_address) = raw_address_value else {
|
||||||
|
panic!("Expected PointerImpl.raw_address to be a DvmValue::Long, but got: {:?}", raw_address_value);
|
||||||
|
};
|
||||||
|
let ptr = raw_address as usize as *mut u8;
|
||||||
|
for (j, b) in s.bytes().enumerate() {
|
||||||
|
ptr.offset(j as isize).write(b);
|
||||||
|
}
|
||||||
|
self.registers.insert(target_register, DvmValue::Pointer(pointer_object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Invalid constant type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Could not find lib: {}", lib_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
PLATFORM_CALL => {
|
PLATFORM_CALL => {
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
@ -169,7 +305,47 @@ impl DmVirtualMachine {
|
|||||||
let call_result = platform_function(args, self);
|
let call_result = platform_function(args, self);
|
||||||
self.registers.insert(return_register, call_result);
|
self.registers.insert(return_register, call_result);
|
||||||
}
|
}
|
||||||
_ => panic!("Invalid code instruction"),
|
INVOKE_FN => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
INVOKE_VIRTUAL => {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
INVOKE_METHOD => {
|
||||||
|
i += 1;
|
||||||
|
let name_length = get_32_le!(code, i, 0, usize);
|
||||||
|
i += 4;
|
||||||
|
let name_raw = code[i..(i + name_length)].to_vec();
|
||||||
|
i += name_length;
|
||||||
|
let arg_registers_length = code[i] as usize;
|
||||||
|
i += 1;
|
||||||
|
let arg_registers = code[i..(i + arg_registers_length)].to_vec();
|
||||||
|
i += arg_registers_length;
|
||||||
|
|
||||||
|
let method_name = String::from_utf8(name_raw).unwrap();
|
||||||
|
|
||||||
|
let method = self
|
||||||
|
.get_fn_by_fqn(&method_name)
|
||||||
|
.expect(&format!("Could not find method: {}", method_name));
|
||||||
|
|
||||||
|
let mut args: Vec<DvmValue> = Vec::new();
|
||||||
|
for arg_register in arg_registers {
|
||||||
|
let register_value = self.registers.get(arg_register as usize).unwrap();
|
||||||
|
args.push(register_value.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.call_fn(method.as_ref(), args);
|
||||||
|
}
|
||||||
|
INVOKE_DYNAMIC => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
RETURN => {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
RETURN_REGISTER => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
op_code => panic!("Invalid or unimplemented op code: {:#04x}", op_code),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,6 +400,7 @@ mod dvm_run_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[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);
|
||||||
@ -240,6 +417,7 @@ mod dvm_run_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[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);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::vm::dm_type::DmPrimitiveType;
|
use crate::vm::dm_type::DmType;
|
||||||
use crate::vm::mem::DmAllocObject;
|
use crate::vm::mem::DmAllocObject;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -13,9 +13,35 @@ pub enum DmObjectType {
|
|||||||
pub struct DmFn {
|
pub struct DmFn {
|
||||||
pub fqn: String,
|
pub fqn: String,
|
||||||
pub short_name: String,
|
pub short_name: String,
|
||||||
pub implements: Option<DmVirtualMethod>,
|
|
||||||
pub byte_code: Vec<u8>,
|
pub byte_code: Vec<u8>,
|
||||||
pub num_registers: usize,
|
pub number_used_registers: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DmFn {
|
||||||
|
pub fn new(fqn: &str, short_name: &str, byte_code: Vec<u8>, number_used_registers: usize) -> Self {
|
||||||
|
DmFn {
|
||||||
|
fqn: fqn.to_string(),
|
||||||
|
short_name: short_name.to_string(),
|
||||||
|
byte_code,
|
||||||
|
number_used_registers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fqn(&self) -> &str {
|
||||||
|
self.fqn.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn short_name(&self) -> &str {
|
||||||
|
self.short_name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn byte_code(&self) -> &Vec<u8> {
|
||||||
|
&self.byte_code
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn number_used_registers(&self) -> usize {
|
||||||
|
self.number_used_registers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DmFn {
|
impl PartialEq for DmFn {
|
||||||
@ -24,13 +50,33 @@ impl PartialEq for DmFn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq)]
|
||||||
|
pub struct DmMethod {
|
||||||
|
dm_fn: Rc<DmFn>,
|
||||||
|
implements: Option<Rc<DmVirtualMethod>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for DmMethod {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.dm_fn == other.dm_fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DmMethod {
|
||||||
|
pub fn new(dm_fn: DmFn, implements: Option<Rc<DmVirtualMethod>>) -> Self {
|
||||||
|
DmMethod {
|
||||||
|
dm_fn: Rc::new(dm_fn),
|
||||||
|
implements,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq)]
|
#[derive(Debug, Eq)]
|
||||||
pub struct DmInterface {
|
pub struct DmInterface {
|
||||||
pub fqn: String,
|
fqn: String,
|
||||||
short_name: String,
|
short_name: String,
|
||||||
properties: Vec<Rc<DmProperty>>,
|
functions: Vec<Rc<DmFn>>,
|
||||||
virtual_methods: Vec<Rc<DmVirtualMethod>>,
|
virtual_methods: Vec<Rc<DmVirtualMethod>>,
|
||||||
impl_methods: Vec<Rc<DmFn>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DmInterface {
|
impl PartialEq for DmInterface {
|
||||||
@ -40,10 +86,37 @@ impl PartialEq for DmInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DmInterface {
|
impl DmInterface {
|
||||||
pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmFn>> {
|
pub fn new(fqn: &str, short_name: &str) -> Self {
|
||||||
if let Some(dm_fn) = self.impl_methods.iter().find(|&dm_fn| dm_fn.fqn == name) {
|
DmInterface {
|
||||||
return Some(dm_fn.clone());
|
fqn: fqn.to_string(),
|
||||||
} else if self
|
short_name: short_name.to_string(),
|
||||||
|
functions: Vec::new(),
|
||||||
|
virtual_methods: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fqn(&self) -> &str {
|
||||||
|
self.fqn.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn short_name(&self) -> &str {
|
||||||
|
self.short_name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_function(&mut self, dm_fn: DmFn) {
|
||||||
|
self.functions.push(Rc::new(dm_fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_functions(&self) -> Vec<Rc<DmFn>> {
|
||||||
|
self.functions.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_method(&mut self, dm_virtual_method: DmVirtualMethod) {
|
||||||
|
self.virtual_methods.push(Rc::new(dm_virtual_method));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmMethod>> {
|
||||||
|
if self
|
||||||
.virtual_methods
|
.virtual_methods
|
||||||
.iter()
|
.iter()
|
||||||
.find(|&dm_fn| dm_fn.fqn == name)
|
.find(|&dm_fn| dm_fn.fqn == name)
|
||||||
@ -53,6 +126,10 @@ impl DmInterface {
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_virtual_methods(&self) -> Vec<Rc<DmVirtualMethod>> {
|
||||||
|
self.virtual_methods.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmProperty> {
|
pub fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmProperty> {
|
||||||
todo!()
|
todo!()
|
||||||
@ -75,11 +152,10 @@ impl PartialEq for DmVirtualMethod {
|
|||||||
pub struct DmImplementation {
|
pub struct DmImplementation {
|
||||||
pub fqn: String,
|
pub fqn: String,
|
||||||
pub short_name: String,
|
pub short_name: String,
|
||||||
pub interface: Rc<DmInterface>,
|
pub interface: Option<Rc<DmInterface>>,
|
||||||
pub size_in_bytes: usize,
|
pub functions: Vec<Rc<DmFn>>,
|
||||||
properties: Vec<DmProperty>,
|
pub methods: Vec<Rc<DmMethod>>,
|
||||||
fields: Vec<DmField>,
|
pub fields: Vec<DmField>,
|
||||||
methods: Vec<Rc<DmFn>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DmImplementation {
|
impl PartialEq for DmImplementation {
|
||||||
@ -89,9 +165,24 @@ impl PartialEq for DmImplementation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DmImplementation {
|
impl DmImplementation {
|
||||||
pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmFn>> {
|
pub fn new(fqn: &str, short_name: &str, interface: Option<Rc<DmInterface>>) -> Self {
|
||||||
|
DmImplementation {
|
||||||
|
fqn: fqn.to_string(),
|
||||||
|
short_name: short_name.to_string(),
|
||||||
|
interface,
|
||||||
|
functions: Vec::new(),
|
||||||
|
methods: Vec::new(),
|
||||||
|
fields: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interface(&self) -> Option<Rc<DmInterface>> {
|
||||||
|
self.interface.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmMethod>> {
|
||||||
for method in &self.methods {
|
for method in &self.methods {
|
||||||
if method.fqn == name {
|
if method.dm_fn.fqn == name {
|
||||||
return Some(method.clone());
|
return Some(method.clone());
|
||||||
} else if let Some(implements) = &method.implements {
|
} else if let Some(implements) = &method.implements {
|
||||||
if implements.fqn == name {
|
if implements.fqn == name {
|
||||||
@ -106,8 +197,12 @@ impl DmImplementation {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmField>> {
|
pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmField> {
|
||||||
todo!()
|
self.fields.iter().find(|field| field.name == name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size_in_bytes(&self) -> usize {
|
||||||
|
self.fields.iter().map(|field| field.size_in_bytes()).sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +210,7 @@ impl DmImplementation {
|
|||||||
pub struct DmProperty {
|
pub struct DmProperty {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub data_offset: usize,
|
pub data_offset: usize,
|
||||||
pub primitive_type: Rc<DmPrimitiveType>,
|
pub primitive_type: Rc<DmType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DmProperty {
|
impl PartialEq for DmProperty {
|
||||||
@ -127,7 +222,8 @@ impl PartialEq for DmProperty {
|
|||||||
#[derive(Debug, Eq)]
|
#[derive(Debug, Eq)]
|
||||||
pub struct DmField {
|
pub struct DmField {
|
||||||
name: String,
|
name: String,
|
||||||
primitive_type: Rc<DmPrimitiveType>,
|
dm_type: DmType,
|
||||||
|
data_offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DmField {
|
impl PartialEq for DmField {
|
||||||
@ -135,3 +231,29 @@ impl PartialEq for DmField {
|
|||||||
self.name == other.name
|
self.name == other.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DmField {
|
||||||
|
pub fn new(name: &str, dm_type: DmType, data_offset: usize) -> Self {
|
||||||
|
DmField {
|
||||||
|
name: name.to_string(),
|
||||||
|
dm_type,
|
||||||
|
data_offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dm_type(&self) -> &DmType {
|
||||||
|
&self.dm_type
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_offset(&self) -> usize {
|
||||||
|
self.data_offset
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size_in_bytes(&self) -> usize {
|
||||||
|
self.dm_type.size_in_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -37,7 +37,23 @@ 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;
|
||||||
|
|
||||||
|
pub const MOV_CONST: u8 = 0x0b;
|
||||||
|
|
||||||
|
pub const ALLOC_RAW: u8 = 0x0c;
|
||||||
|
pub const ALLOC_RAW_FROM: u8 = 0x0d;
|
||||||
|
|
||||||
pub const PLATFORM_CALL: u8 = 0x10;
|
pub const PLATFORM_CALL: u8 = 0x10;
|
||||||
|
pub const INVOKE_FN: u8 = 0x11;
|
||||||
|
pub const INVOKE_VIRTUAL: u8 = 0x12;
|
||||||
|
pub const INVOKE_METHOD: u8 = 0x13;
|
||||||
|
pub const INVOKE_DYNAMIC: u8 = 0x14;
|
||||||
|
|
||||||
|
pub const RETURN: u8 = 0x20;
|
||||||
|
pub const RETURN_REGISTER: u8 = 0x21;
|
||||||
|
|
||||||
|
pub const MOV_SIZE_OF: u8 = 0x30;
|
||||||
|
|
||||||
|
pub const MULTIPLY: u8 = 0x40;
|
||||||
|
|
||||||
macro_rules! push_number {
|
macro_rules! push_number {
|
||||||
( $dest: expr, $num: expr ) => {
|
( $dest: expr, $num: expr ) => {
|
||||||
@ -63,10 +79,24 @@ pub fn add_mov_register(code: &mut Vec<u8>, target_register: u8, source_register
|
|||||||
code.push(source_register);
|
code.push(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, implementation_name: &str) {
|
||||||
code.push(ALLOC);
|
code.push(ALLOC);
|
||||||
code.push(register);
|
code.push(register);
|
||||||
push_number!(code, size);
|
push_number!(code, size);
|
||||||
|
push_number!(code, implementation_name.len() as u32);
|
||||||
|
push_string!(code, implementation_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_alloc_raw(code: &mut Vec<u8>, target_register: u8, size: u32) {
|
||||||
|
code.push(ALLOC_RAW);
|
||||||
|
code.push(target_register);
|
||||||
|
push_number!(code, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_alloc_raw_from(code: &mut Vec<u8>, target_register: u8, source_register: u8) {
|
||||||
|
code.push(ALLOC_RAW_FROM);
|
||||||
|
code.push(target_register);
|
||||||
|
push_number!(code, source_register);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_dealloc(code: &mut Vec<u8>, register: u8) {
|
pub fn add_dealloc(code: &mut Vec<u8>, register: u8) {
|
||||||
@ -81,7 +111,33 @@ 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, return_register: u8, arg_registers_length: u8, arg_registers: &Vec<u8>) {
|
pub fn add_mov_register_to(
|
||||||
|
code: &mut Vec<u8>,
|
||||||
|
target_register: u8,
|
||||||
|
offset: u32,
|
||||||
|
source_register: u8,
|
||||||
|
) {
|
||||||
|
code.push(MOV_REGISTER_TO);
|
||||||
|
code.push(target_register);
|
||||||
|
push_number!(code, offset);
|
||||||
|
code.push(source_register);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_mov_const(code: &mut Vec<u8>, register: u8, lib_name: &str, const_id: u32) {
|
||||||
|
code.push(MOV_CONST);
|
||||||
|
code.push(register);
|
||||||
|
push_number!(code, lib_name.len() as u32);
|
||||||
|
push_string!(code, lib_name);
|
||||||
|
push_number!(code, const_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_platform_call(
|
||||||
|
code: &mut Vec<u8>,
|
||||||
|
symbol_name: &str,
|
||||||
|
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() as u32);
|
push_number!(code, symbol_name.len() as u32);
|
||||||
push_string!(code, symbol_name);
|
push_string!(code, symbol_name);
|
||||||
@ -91,3 +147,51 @@ pub fn add_platform_call_to(code: &mut Vec<u8>, symbol_name: &String, return_reg
|
|||||||
code.push(b);
|
code.push(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_invoke_fn(code: &mut Vec<u8>, fn_name: &str, return_register: u8, arg_registers: &[u8]) {
|
||||||
|
code.push(INVOKE_FN);
|
||||||
|
push_number!(code, fn_name.len() as u32);
|
||||||
|
push_string!(code, fn_name);
|
||||||
|
push_number!(code, return_register);
|
||||||
|
push_number!(code, arg_registers.len() as u8);
|
||||||
|
for &b in arg_registers {
|
||||||
|
code.push(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_invoke_method(code: &mut Vec<u8>, name: &str, arg_registers: &[u8]) {
|
||||||
|
code.push(INVOKE_METHOD);
|
||||||
|
push_number!(code, name.len() as u32);
|
||||||
|
push_string!(code, name);
|
||||||
|
push_number!(code, arg_registers.len() as u8);
|
||||||
|
for &b in arg_registers {
|
||||||
|
code.push(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_ret(code: &mut Vec<u8>) {
|
||||||
|
code.push(RETURN);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_ret_register(code: &mut Vec<u8>, register: u8) {
|
||||||
|
code.push(RETURN_REGISTER);
|
||||||
|
code.push(register);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_mov_size_of(code: &mut Vec<u8>, target_register: u8, source_register: u8) {
|
||||||
|
code.push(MOV_SIZE_OF);
|
||||||
|
code.push(target_register);
|
||||||
|
code.push(source_register);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_multiply(
|
||||||
|
code: &mut Vec<u8>,
|
||||||
|
target_register: u8,
|
||||||
|
left_register: u8,
|
||||||
|
right_register: u8,
|
||||||
|
) {
|
||||||
|
code.push(MULTIPLY);
|
||||||
|
code.push(target_register);
|
||||||
|
code.push(left_register);
|
||||||
|
code.push(right_register);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::vm::dvm_value::DvmValue;
|
use crate::vm::dvm_value::DvmValue;
|
||||||
use crate::vm::mem::DmAllocObject;
|
use crate::vm::mem::{get_field_value, DmAllocObject};
|
||||||
use crate::vm::DmVirtualMachine;
|
use crate::vm::DmVirtualMachine;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -7,7 +7,9 @@ pub fn dm_print(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
|
|||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
return DvmValue::Unit; // TODO: make exception
|
return DvmValue::Unit; // TODO: make exception
|
||||||
}
|
}
|
||||||
print!("{}", get_string(&args[0], vm));
|
unsafe {
|
||||||
|
print!("{}", get_string(&args[0], vm));
|
||||||
|
}
|
||||||
DvmValue::Unit
|
DvmValue::Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,11 +17,13 @@ pub fn dm_println(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
|
|||||||
if args.len() != 1 {
|
if args.len() != 1 {
|
||||||
return DvmValue::Unit;
|
return DvmValue::Unit;
|
||||||
}
|
}
|
||||||
println!("{}", get_string(&args[0], vm));
|
unsafe {
|
||||||
|
println!("{}", get_string(&args[0], vm));
|
||||||
|
}
|
||||||
DvmValue::Unit
|
DvmValue::Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String {
|
unsafe fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String {
|
||||||
match dvm_value {
|
match dvm_value {
|
||||||
DvmValue::Byte(b) => b.to_string(),
|
DvmValue::Byte(b) => b.to_string(),
|
||||||
DvmValue::Int(i) => i.to_string(),
|
DvmValue::Int(i) => i.to_string(),
|
||||||
@ -27,24 +31,66 @@ fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String {
|
|||||||
DvmValue::Double(d) => d.to_string(),
|
DvmValue::Double(d) => d.to_string(),
|
||||||
DvmValue::Boolean(b) => b.to_string(),
|
DvmValue::Boolean(b) => b.to_string(),
|
||||||
DvmValue::Pointer(alloc_object_rc) => convert_to_string(alloc_object_rc.clone(), vm),
|
DvmValue::Pointer(alloc_object_rc) => convert_to_string(alloc_object_rc.clone(), vm),
|
||||||
DvmValue::ByteArray(_) => todo!(),
|
|
||||||
DvmValue::IntArray(_) => todo!(),
|
|
||||||
DvmValue::LongArray(_) => todo!(),
|
|
||||||
DvmValue::DoubleArray(_) => todo!(),
|
|
||||||
DvmValue::BooleanArray(_) => todo!(),
|
|
||||||
DvmValue::PointerArray(_) => todo!(),
|
|
||||||
DvmValue::Unit => String::from("Unit"),
|
DvmValue::Unit => String::from("Unit"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_to_string(alloc_object_rc: Rc<DmAllocObject>, vm: &mut DmVirtualMachine) -> String {
|
unsafe fn convert_to_string(
|
||||||
let to_string_result = vm.call_by_fqn(
|
alloc_object_rc: Rc<DmAllocObject>,
|
||||||
"std::Display::to_string",
|
vm: &mut DmVirtualMachine,
|
||||||
vec![DvmValue::Pointer(alloc_object_rc)],
|
) -> String {
|
||||||
);
|
if alloc_object_rc.implementation.fqn == "std::core::String" {
|
||||||
if let DvmValue::Pointer(to_string_result_alloc_object) = to_string_result {
|
let bytes_field = alloc_object_rc
|
||||||
todo!("Convert to_string_result_alloc_object (a String) to bytes to pass to print")
|
.implementation
|
||||||
|
.get_field("bytes", &alloc_object_rc)
|
||||||
|
.expect("Could not get String.bytes field.");
|
||||||
|
let bytes_value = get_field_value(&bytes_field, &alloc_object_rc);
|
||||||
|
match bytes_value {
|
||||||
|
DvmValue::Pointer(bytes_object) => {
|
||||||
|
if bytes_object.implementation.fqn == "std::core::ArrayImpl" {
|
||||||
|
let pointer_field = bytes_object
|
||||||
|
.implementation
|
||||||
|
.get_field("pointer", &bytes_object)
|
||||||
|
.expect("Could not get ArrayImpl.pointer field.");
|
||||||
|
let pointer_value = get_field_value(&pointer_field, &alloc_object_rc);
|
||||||
|
match pointer_value {
|
||||||
|
DvmValue::Pointer(pointer_object) => {
|
||||||
|
if pointer_object.implementation.fqn == "std::unsafe::PointerImpl" {
|
||||||
|
let raw_address_field = pointer_object.implementation.get_field("raw_address", &pointer_object)
|
||||||
|
.expect("Could not get PointerImpl.raw_address field.");
|
||||||
|
let raw_address_value = get_field_value(raw_address_field, &alloc_object_rc);
|
||||||
|
|
||||||
|
let size_field = pointer_object.implementation.get_field("size", &alloc_object_rc)
|
||||||
|
.expect("Could not get PointerImpl.size field.");
|
||||||
|
let size_value = get_field_value(&size_field, &alloc_object_rc);
|
||||||
|
let DvmValue::Long(size) = size_value else {
|
||||||
|
panic!("Expected PointerImpl.size to be a Long");
|
||||||
|
};
|
||||||
|
|
||||||
|
match raw_address_value {
|
||||||
|
DvmValue::Long(raw_address) => {
|
||||||
|
let raw_bytes_pointer = raw_address as usize as *mut u8;
|
||||||
|
let mut v: Vec<u8> = Vec::new();
|
||||||
|
for i in 0..(size as isize) {
|
||||||
|
v.push(raw_bytes_pointer.offset(i).read());
|
||||||
|
}
|
||||||
|
String::from_utf8(v).unwrap()
|
||||||
|
}
|
||||||
|
_ => panic!("Expected raw_address to be a Long.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Expected ArrayImpl.pointer to be a Pointer to PointerImpl, instead found: {:?}", pointer_object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Expected ArrayImpl.pointer to be a Pointer, instead found: {:?}", pointer_value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Expected String.bytes to be a Pointer to an ArrayImpl, instead found: {:?}", bytes_object.implementation.fqn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Expected String.bytes to be a Pointer, instead found: {:?}", bytes_value),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("to_string did not return a pointer")
|
todo!("what happens if we don't have a String?")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user