Various work on running byte code.
This commit is contained in:
parent
6190beaed2
commit
d5153cc9fb
@ -12,7 +12,7 @@ pub int Array<T> : Monad + Default + Empty {
|
||||
|
||||
impl ArrayImpl<T> : Array<T> {
|
||||
|
||||
fld pointer: Pointer<T>
|
||||
fld pointer: Pointer
|
||||
fld length: Int
|
||||
|
||||
pub unsafe ctor(length: Int) {
|
||||
@ -20,12 +20,12 @@ impl ArrayImpl<T> : Array<T> {
|
||||
self.length = length
|
||||
}
|
||||
|
||||
pub ctor(pointer: Pointer<T>, length: Int) {
|
||||
pub ctor(pointer: Pointer, length: Int) {
|
||||
self.pointer = pointer
|
||||
self.length = length
|
||||
}
|
||||
|
||||
pub unsafe fn set(index: Int, item: Pointer<T>) {
|
||||
pub unsafe fn set(index: Int, item: Pointer) {
|
||||
pointer.offset(index * T::size()).write(item.read())
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,7 @@ pub int String : Display {
|
||||
|
||||
}
|
||||
|
||||
impl Utf8String(bytes: Array<Byte>) : String {
|
||||
encoding = Encoding::Utf8
|
||||
impl StringImpl(bytes: Array<Byte>, /* encoding: Encoding */) {
|
||||
length = bytes.length
|
||||
characters = lazy {
|
||||
todo('parse the utf8 bytes and return an Array<Character>')
|
||||
@ -27,6 +26,6 @@ pub mod string {
|
||||
// let bytes = array::of(0x64, 0x65, 0x69, 0x6d, 0x6f, 0x73)
|
||||
// let s = string::from_utf8_bytes(bytes)
|
||||
// println s // "deimos"
|
||||
fn from_utf8_bytes(bytes: Array<Byte>): String = Utf8String(bytes)
|
||||
fn from_utf8_bytes(bytes: Array<Byte>): String = StringImpl(bytes, /* Encoding::Utf8 */)
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,14 @@
|
||||
ns std::unsafe
|
||||
|
||||
pub int Pointer<T> {}
|
||||
pub int Pointer
|
||||
|
||||
impl PointerImpl<T> {
|
||||
|
||||
fld raw_address: Long
|
||||
fld size: Long
|
||||
|
||||
decl ctor(size: Long)
|
||||
|
||||
}
|
||||
// Contains two fields:
|
||||
// fld raw_address: Long
|
||||
// fld size: Long
|
||||
decl impl PointerImpl(size: Long) : Pointer
|
||||
|
||||
pub mod mem {
|
||||
|
||||
pub fn <T> alloc(size: Long): Pointer<T> = PointerImpl(size)
|
||||
pub fn alloc(size: Long): Pointer = PointerImpl(size)
|
||||
|
||||
}
|
||||
|
@ -9,5 +9,23 @@ pub enum DvmValue {
|
||||
Double(f64),
|
||||
Boolean(bool),
|
||||
Pointer(Rc<DmAllocObject>),
|
||||
Unit,
|
||||
Uninit,
|
||||
}
|
||||
|
||||
impl DvmValue {
|
||||
pub fn expect_long(&self) -> i64 {
|
||||
if let DvmValue::Long(l) = self {
|
||||
*l
|
||||
} else {
|
||||
panic!("Expected DvmValue::long, but found {:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_pointer(&self) -> Rc<DmAllocObject> {
|
||||
if let DvmValue::Pointer(p) = self {
|
||||
p.clone()
|
||||
} else {
|
||||
panic!("Expected DvmValue::Pointer, but found {:?}", self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ impl DmLib {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DmConstant {
|
||||
String(String),
|
||||
}
|
||||
|
@ -1,17 +1,40 @@
|
||||
use crate::vm::dm_type::DmType;
|
||||
use crate::vm::dvm_value::DvmValue;
|
||||
use crate::vm::object_type::{DmField, DmImplementation};
|
||||
use std::alloc::Layout;
|
||||
use std::alloc::{alloc, dealloc, Layout};
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct DmAllocObject {
|
||||
pub data: *mut u8,
|
||||
pub units: HashSet<usize>,
|
||||
pub size: usize,
|
||||
pub layout: Layout,
|
||||
pub implementation: Rc<DmImplementation>,
|
||||
}
|
||||
|
||||
impl DmAllocObject {
|
||||
pub fn new(size: usize, implementation: Rc<DmImplementation>) -> Self {
|
||||
let layout = Layout::from_size_align(size, 1).unwrap();
|
||||
DmAllocObject {
|
||||
data: unsafe { alloc(layout) },
|
||||
units: HashSet::new(),
|
||||
size,
|
||||
layout,
|
||||
implementation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DmAllocObject {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
dealloc(self.data, self.layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -> DvmValue {
|
||||
let data_size = dm_field.dm_type().size_in_bytes();
|
||||
let mut raw_data: Vec<u8> = Vec::with_capacity(data_size);
|
||||
@ -29,13 +52,13 @@ pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -
|
||||
DmType::Double => DvmValue::Double(f64::from_ne_bytes(
|
||||
raw_data[0..data_size].try_into().unwrap(),
|
||||
)),
|
||||
DmType::Boolean => DvmValue::Boolean(raw_data[0] == 1),
|
||||
DmType::Boolean => DvmValue::Boolean(raw_data[0] != 0),
|
||||
DmType::Pointer => {
|
||||
// read the pointer's (address) value
|
||||
let address = usize::from_ne_bytes(raw_data[0..data_size].try_into().unwrap());
|
||||
DvmValue::Pointer(Rc::from_raw(address as *const DmAllocObject))
|
||||
}
|
||||
DmType::Unit => DvmValue::Unit,
|
||||
DmType::Unit => DvmValue::Uninit,
|
||||
}
|
||||
}
|
||||
|
||||
|
465
src/vm/mod.rs
465
src/vm/mod.rs
@ -13,7 +13,7 @@ use crate::vm::mem::{get_field_value, DmAllocObject};
|
||||
use crate::vm::object_type::DmFn;
|
||||
use crate::vm::platform::init_platform_functions;
|
||||
use op_codes::*;
|
||||
use std::alloc::{alloc, Layout};
|
||||
use std::alloc::{alloc, dealloc, Layout};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use util::{get_32_le, get_64_le};
|
||||
@ -21,19 +21,15 @@ use util::{get_32_le, get_64_le};
|
||||
pub type PlatformFunction = fn(args: Vec<DvmValue>, &mut DmVirtualMachine) -> DvmValue;
|
||||
|
||||
enum CallFrame {
|
||||
PlatformCall(PlatformCallFrame),
|
||||
DeimosCall(DeimosCallFrame),
|
||||
PlatformCall(CallFrameInfo),
|
||||
DeimosCall(CallFrameInfo),
|
||||
}
|
||||
|
||||
pub struct PlatformCallFrame {
|
||||
pub name: String,
|
||||
pub args: Vec<DvmValue>,
|
||||
}
|
||||
|
||||
struct DeimosCallFrame {
|
||||
return_address: usize,
|
||||
struct CallFrameInfo {
|
||||
fn_fqn: String,
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub struct DmVirtualMachine {
|
||||
libs: Vec<DmLib>,
|
||||
functions: HashMap<String, Rc<DmFn>>,
|
||||
@ -44,19 +40,59 @@ pub struct DmVirtualMachine {
|
||||
register_state_stack: Vec<Vec<DvmValue>>,
|
||||
}
|
||||
|
||||
pub struct DvmContext {
|
||||
libs: Vec<DmLib>,
|
||||
functions: HashMap<String, Rc<DmFn>>,
|
||||
platform_functions: HashMap<String, Rc<PlatformFunction>>,
|
||||
}
|
||||
|
||||
impl DvmContext {
|
||||
pub fn new() -> Self {
|
||||
DvmContext {
|
||||
libs: Vec::new(),
|
||||
functions: HashMap::new(),
|
||||
platform_functions: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fn_by_fqn(&self, fqn: &str) -> Option<Rc<DmFn>> {
|
||||
self.functions.get(fqn).cloned()
|
||||
}
|
||||
|
||||
pub fn platform_fn_by_fqn(&self, fqn: &str) -> Option<Rc<PlatformFunction>> {
|
||||
self.platform_functions.get(fqn).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DvmState {
|
||||
call_stack: Vec<CallFrame>,
|
||||
registers: Vec<DvmValue>,
|
||||
register_state_stack: Vec<Vec<DvmValue>>,
|
||||
}
|
||||
|
||||
impl DvmState {
|
||||
pub fn new() -> Self {
|
||||
DvmState {
|
||||
call_stack: Vec::new(),
|
||||
registers: Vec::new(),
|
||||
register_state_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn load_functions(destination: &mut HashMap<String, Rc<DmFn>>, libs: &Vec<DmLib>) {
|
||||
for module in libs {
|
||||
for lib_fn in &module.functions {
|
||||
for lib in libs {
|
||||
for lib_fn in &lib.functions {
|
||||
destination.insert(lib_fn.fqn.clone(), lib_fn.clone());
|
||||
}
|
||||
for interface_function in module
|
||||
for interface_function in lib
|
||||
.interfaces
|
||||
.iter()
|
||||
.flat_map(|interface| interface.get_functions())
|
||||
{
|
||||
destination.insert(interface_function.fqn.clone(), interface_function.clone());
|
||||
}
|
||||
for implementation_function in module
|
||||
for implementation_function in lib
|
||||
.implementations
|
||||
.iter()
|
||||
.flat_map(|implementation| &implementation.functions)
|
||||
@ -69,6 +105,367 @@ fn load_functions(destination: &mut HashMap<String, Rc<DmFn>>, libs: &Vec<DmLib>
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_fn(
|
||||
state: &mut DvmState,
|
||||
context: &DvmContext,
|
||||
dm_fn: &DmFn,
|
||||
args: Vec<DvmValue>,
|
||||
) -> Option<DvmValue> {
|
||||
// save current state
|
||||
state.call_stack.push(CallFrame::DeimosCall(CallFrameInfo {
|
||||
fn_fqn: dm_fn.fqn.clone(),
|
||||
}));
|
||||
state.register_state_stack.push(state.registers.clone());
|
||||
|
||||
// zero registers and make sure there are enough for dm_function
|
||||
state.registers.clear();
|
||||
if state.registers.len() < dm_fn.number_used_registers() {
|
||||
state
|
||||
.registers
|
||||
.resize(dm_fn.number_used_registers(), DvmValue::Uninit);
|
||||
}
|
||||
|
||||
// push args
|
||||
for arg in args {
|
||||
state.registers.push(arg);
|
||||
}
|
||||
|
||||
// run the byte code
|
||||
run_byte_code(state, context, &dm_fn.byte_code);
|
||||
|
||||
// get return value
|
||||
let return_value = state
|
||||
.registers
|
||||
.get(dm_fn.return_register() as usize)
|
||||
.map(|m| m.clone());
|
||||
|
||||
// restore state
|
||||
state.registers = state.register_state_stack.pop().unwrap();
|
||||
state.call_stack.pop();
|
||||
|
||||
// return result
|
||||
return_value
|
||||
}
|
||||
|
||||
macro_rules! next_8 {
|
||||
( $byte_code: expr, $T: ident ) => {
|
||||
$byte_code.next().unwrap() as $T
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! next_32_le {
|
||||
( $byte_code: expr, $T: ident ) => {
|
||||
next_8!($byte_code, $T)
|
||||
+ (next_8!($byte_code, $T) << 8)
|
||||
+ (next_8!($byte_code, $T) << 16)
|
||||
+ (next_8!($byte_code, $T) << 24)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! next_64_le {
|
||||
( $byte_code: expr, $T: ident ) => {
|
||||
next_8!($byte_code, $T)
|
||||
+ (next_8!($byte_code, $T) << 8)
|
||||
+ (next_8!($byte_code, $T) << 16)
|
||||
+ (next_8!($byte_code, $T) << 24)
|
||||
+ (next_8!($byte_code, $T) << 32)
|
||||
+ (next_8!($byte_code, $T) << 40)
|
||||
+ (next_8!($byte_code, $T) << 48)
|
||||
+ (next_8!($byte_code, $T) << 56)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_string {
|
||||
( $iter: expr ) => {{
|
||||
let str_length = next_32_le!($iter, usize);
|
||||
let mut str_raw: Vec<u8> = Vec::new();
|
||||
let mut i = 0;
|
||||
while i < str_length {
|
||||
str_raw.push($iter.next().unwrap());
|
||||
i += 1;
|
||||
}
|
||||
String::from_utf8(str_raw).unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! write_string {
|
||||
( $raw_ptr: expr, $s: expr ) => {
|
||||
for (i, b) in $s.bytes().enumerate() {
|
||||
unsafe {
|
||||
$raw_ptr.add(i).write(b);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_bytes {
|
||||
( $ptr: expr, $offset: expr, $src: expr ) => {
|
||||
for (i, &b) in $src.iter().enumerate() {
|
||||
unsafe {
|
||||
$ptr.add($offset + i).write(b);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8]) {
|
||||
let mut iter = byte_code.iter().cloned();
|
||||
while let Some(op_code) = iter.next() {
|
||||
match op_code {
|
||||
MOV_INT => {
|
||||
let target_register = next_8!(iter, usize);
|
||||
let operand = next_32_le!(iter, u32) as i32;
|
||||
state
|
||||
.registers
|
||||
.insert(target_register, DvmValue::Int(operand));
|
||||
}
|
||||
MOV_LONG => {
|
||||
let target_register = next_8!(iter, usize);
|
||||
let operand = next_64_le!(iter, u64) as i64;
|
||||
state
|
||||
.registers
|
||||
.insert(target_register, DvmValue::Long(operand));
|
||||
}
|
||||
MOV_DOUBLE => {
|
||||
let target_register = next_8!(iter, usize);
|
||||
let operand = next_64_le!(iter, u64) as f64;
|
||||
state
|
||||
.registers
|
||||
.insert(target_register, DvmValue::Double(operand));
|
||||
}
|
||||
MOV_REGISTER => {
|
||||
let target_register = next_8!(iter, usize);
|
||||
let source_register = next_8!(iter, usize);
|
||||
let source_value = state.registers.get(source_register).unwrap();
|
||||
state
|
||||
.registers
|
||||
.insert(target_register, source_value.clone())
|
||||
}
|
||||
ALLOC => {
|
||||
let target_register = next_8!(iter, usize);
|
||||
let alloc_size = next_32_le!(iter, usize);
|
||||
let impl_name = read_string!(iter);
|
||||
|
||||
let implementation = context
|
||||
.libs
|
||||
.iter()
|
||||
.find_map(|lib| {
|
||||
lib.implementations
|
||||
.iter()
|
||||
.find(|implementation| implementation.fqn == impl_name)
|
||||
})
|
||||
.expect(&format!("Implementation not found: {}", impl_name));
|
||||
|
||||
let dm_alloc_object = DmAllocObject::new(alloc_size, implementation.clone());
|
||||
let dvm_pointer = DvmValue::Pointer(Rc::new(dm_alloc_object));
|
||||
state.registers.insert(target_register, dvm_pointer);
|
||||
}
|
||||
DEALLOC => {
|
||||
let target_register = next_8!(iter, usize);
|
||||
let dm_alloc_object = state.registers
|
||||
.remove(target_register)
|
||||
.expect_pointer();
|
||||
drop(dm_alloc_object); // explicit
|
||||
}
|
||||
MOV_INT_TO => {
|
||||
let target_register = next_8!(iter, usize);
|
||||
let offset = next_32_le!(iter, usize);
|
||||
let operand = next_32_le!(iter, u32) as i32;
|
||||
|
||||
let dm_alloc_object = state
|
||||
.registers
|
||||
.get(target_register)
|
||||
.unwrap()
|
||||
.expect_pointer();
|
||||
write_bytes!(dm_alloc_object.data, offset, operand.to_ne_bytes());
|
||||
}
|
||||
MOV_LONG_TO => {
|
||||
todo!()
|
||||
}
|
||||
MOV_DOUBLE_TO => {
|
||||
todo!()
|
||||
}
|
||||
MOV_REGISTER_TO => {
|
||||
// Moves the value from the source register to the object pointed to by the target
|
||||
// register, at the given offset.
|
||||
let target_register = next_8!(iter, usize);
|
||||
let offset = next_32_le!(iter, usize);
|
||||
let source_register = next_8!(iter, usize);
|
||||
|
||||
let target_alloc_object = state
|
||||
.registers
|
||||
.get(target_register)
|
||||
.unwrap()
|
||||
.expect_pointer();
|
||||
|
||||
let source_value = state.registers.get(source_register).unwrap();
|
||||
match source_value {
|
||||
DvmValue::Int(i) => {
|
||||
write_bytes!(target_alloc_object.data, offset, i.to_ne_bytes());
|
||||
}
|
||||
DvmValue::Byte(b) => unsafe {
|
||||
target_alloc_object.data.add(offset).write(*b);
|
||||
},
|
||||
DvmValue::Long(l) => {
|
||||
write_bytes!(target_alloc_object.data, offset, l.to_ne_bytes());
|
||||
}
|
||||
DvmValue::Double(d) => {
|
||||
write_bytes!(target_alloc_object.data, offset, d.to_ne_bytes());
|
||||
}
|
||||
DvmValue::Boolean(b) => unsafe {
|
||||
target_alloc_object.data.add(offset).write(*b as u8);
|
||||
},
|
||||
DvmValue::Pointer(source_alloc_object) => {
|
||||
let source_ptr = Rc::into_raw(source_alloc_object.clone());
|
||||
write_bytes!(
|
||||
target_alloc_object.data,
|
||||
offset,
|
||||
(source_ptr as usize).to_ne_bytes()
|
||||
);
|
||||
}
|
||||
DvmValue::Uninit => {
|
||||
panic!("Cannot move DvmValue::Uninit to object.")
|
||||
}
|
||||
}
|
||||
}
|
||||
MOV_CONST => {
|
||||
// TODO: reduce the complexity of this.
|
||||
// Perhaps the target register should just contain a ptr where the data is written.
|
||||
|
||||
// Decode
|
||||
let target_register = next_8!(iter, usize); // must contain an allocated StringImpl
|
||||
let lib_name = read_string!(iter);
|
||||
let const_id = next_8!(iter, usize);
|
||||
let pointer_impl_register = next_8!(iter, usize);
|
||||
let byte_array_impl_register = next_8!(iter, usize);
|
||||
|
||||
// Get constant
|
||||
let Some(lib) = context.libs.iter().find(|lib| lib.name == lib_name) else {
|
||||
panic!("Could not find lib with name: {}", lib_name);
|
||||
};
|
||||
let constant = lib.constants.get(const_id).unwrap();
|
||||
let DmConstant::String(s) = constant;
|
||||
|
||||
// Get allocated PointerImpl
|
||||
let pointer_impl = state
|
||||
.registers
|
||||
.get(pointer_impl_register)
|
||||
.unwrap()
|
||||
.expect_pointer();
|
||||
|
||||
// Init PointerImpl object
|
||||
let pointer_impl_ctor_0_fn = context
|
||||
.functions
|
||||
.get("std::unsafe::PointerImpl::_ctor_0")
|
||||
.expect("Could not find std::unsafe::PointerImpl::_ctor_0");
|
||||
call_fn(
|
||||
state,
|
||||
context,
|
||||
pointer_impl_ctor_0_fn,
|
||||
vec![
|
||||
DvmValue::Pointer(pointer_impl.clone()),
|
||||
DvmValue::Long(s.len() as i64),
|
||||
],
|
||||
);
|
||||
|
||||
// Get std::unsafe::PointerImpl.raw_address field as *mut u8
|
||||
let raw_ptr = unsafe {
|
||||
get_field_value(
|
||||
pointer_impl
|
||||
.implementation
|
||||
.get_field("raw_address", &pointer_impl)
|
||||
.expect("Could not get PointerImpl.raw_address field."),
|
||||
&pointer_impl,
|
||||
)
|
||||
}
|
||||
.expect_long() as usize as *mut u8;
|
||||
|
||||
// Write the constant bytes to the raw_ptr
|
||||
write_string!(raw_ptr, s);
|
||||
|
||||
// Get allocated ArrayImpl<Byte> from byte_array_impl_register
|
||||
let byte_array_impl = state
|
||||
.registers
|
||||
.get(byte_array_impl_register)
|
||||
.unwrap()
|
||||
.expect_pointer();
|
||||
|
||||
// Init ArrayImpl<Byte>
|
||||
let array_ctor_0_fn = context
|
||||
.functions
|
||||
.get("std::core::ArrayImpl::_ctor_1")
|
||||
.expect("Could not find std::core::ArrayImpl::_ctor_1");
|
||||
call_fn(
|
||||
state,
|
||||
context,
|
||||
array_ctor_0_fn,
|
||||
vec![
|
||||
DvmValue::Pointer(byte_array_impl.clone()), // self
|
||||
DvmValue::Pointer(pointer_impl.clone()), // PointerImpl
|
||||
DvmValue::Int(s.len() as i32), // length
|
||||
],
|
||||
);
|
||||
|
||||
// Get allocated StringImpl from string_impl_register
|
||||
let string_impl = state
|
||||
.registers
|
||||
.get(target_register)
|
||||
.unwrap()
|
||||
.expect_pointer();
|
||||
|
||||
// Init StringImpl
|
||||
let string_impl_ctor_0_fn = context
|
||||
.functions
|
||||
.get("std::core::StringImpl::_ctor_0")
|
||||
.expect("Could not find std::core::StringImpl::_ctor_0");
|
||||
call_fn(
|
||||
state,
|
||||
context,
|
||||
string_impl_ctor_0_fn,
|
||||
vec![
|
||||
DvmValue::Pointer(string_impl.clone()),
|
||||
DvmValue::Pointer(byte_array_impl.clone()),
|
||||
],
|
||||
);
|
||||
}
|
||||
ALLOC_RAW => {
|
||||
// Allocates a raw number of bytes, with the number of bytes determined by the
|
||||
// operand
|
||||
todo!()
|
||||
}
|
||||
ALLOC_RAW_FROM => {
|
||||
// Allocates a raw number of bytes, with the number of bytes determined by the value
|
||||
// of the source register
|
||||
todo!()
|
||||
}
|
||||
PLATFORM_CALL => {
|
||||
todo!()
|
||||
}
|
||||
INVOKE_FN => {
|
||||
todo!()
|
||||
}
|
||||
INVOKE_VIRTUAL => {
|
||||
todo!()
|
||||
}
|
||||
INVOKE_DYNAMIC => {
|
||||
todo!()
|
||||
}
|
||||
RETURN_REGISTER => {
|
||||
todo!()
|
||||
}
|
||||
MOV_SIZE_OF => {
|
||||
todo!()
|
||||
}
|
||||
MULTIPLY => {
|
||||
todo!()
|
||||
}
|
||||
op_code => {
|
||||
panic!("Invalid op_code: {}", op_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DmVirtualMachine {
|
||||
pub fn new(libs: Vec<DmLib>) -> DmVirtualMachine {
|
||||
let mut vm = DmVirtualMachine {
|
||||
@ -84,10 +481,12 @@ impl DmVirtualMachine {
|
||||
vm
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn get_fn_by_fqn(&self, fqn: &str) -> Option<Rc<DmFn>> {
|
||||
self.functions.get(fqn).cloned()
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub fn call_fn(&mut self, dm_function: &DmFn, args: Vec<DvmValue>) -> Option<DvmValue> {
|
||||
// save current state
|
||||
self.call_stack.push(CallFrame::DeimosCall(DeimosCallFrame {
|
||||
@ -98,7 +497,7 @@ impl DmVirtualMachine {
|
||||
// zero registers and make sure there are enough for dm_function
|
||||
self.registers.clear();
|
||||
if self.registers.len() < args.len() {
|
||||
self.registers.resize(args.len(), DvmValue::Unit);
|
||||
self.registers.resize(args.len(), DvmValue::Uninit);
|
||||
}
|
||||
|
||||
// push args
|
||||
@ -127,7 +526,7 @@ impl DmVirtualMachine {
|
||||
match code[i] {
|
||||
MOV_INT => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let operand = get_32_le!(code, i, 2, u32);
|
||||
let operand = next_32_le!(code, i, 2, u32);
|
||||
self.registers
|
||||
.insert(target_register, DvmValue::Int(operand as i32));
|
||||
i += 6;
|
||||
@ -153,9 +552,9 @@ impl DmVirtualMachine {
|
||||
i += 1;
|
||||
let target_register = code[i] as usize;
|
||||
i += 1;
|
||||
let alloc_size = get_32_le!(code, i, 0, usize);
|
||||
let alloc_size = next_32_le!(code, i, 0, usize);
|
||||
i += 4;
|
||||
let raw_implementation_name_length = get_32_le!(code, i, 0, usize);
|
||||
let raw_implementation_name_length = next_32_le!(code, i, 0, usize);
|
||||
i += 4;
|
||||
let raw_implementation_name_bytes =
|
||||
code[i..(i + raw_implementation_name_length)].to_vec();
|
||||
@ -201,7 +600,7 @@ impl DmVirtualMachine {
|
||||
i += 1;
|
||||
let target_register = code[i] as usize;
|
||||
i += 1;
|
||||
let offset = get_32_le!(code, i, 0, isize);
|
||||
let offset = next_32_le!(code, i, 0, isize);
|
||||
i += 4;
|
||||
let source_register = code[i] as usize;
|
||||
i += 1;
|
||||
@ -228,11 +627,11 @@ impl DmVirtualMachine {
|
||||
i += 1;
|
||||
let target_register = code[i] as usize;
|
||||
i += 1;
|
||||
let lib_name_length = get_32_le!(code, i, 0, usize);
|
||||
let lib_name_length = next_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);
|
||||
let const_id = next_32_le!(code, i, 0, usize);
|
||||
i += 4;
|
||||
|
||||
let lib_name = String::from_utf8(lib_name_raw).unwrap();
|
||||
@ -241,17 +640,22 @@ impl DmVirtualMachine {
|
||||
let constant = &lib.constants[const_id];
|
||||
match constant {
|
||||
DmConstant::String(s) => {
|
||||
let alloc_fn = self.get_fn_by_fqn("std::unsafe::mem::alloc")
|
||||
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 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)
|
||||
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 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);
|
||||
};
|
||||
@ -259,7 +663,8 @@ impl DmVirtualMachine {
|
||||
for (j, b) in s.bytes().enumerate() {
|
||||
ptr.offset(j as isize).write(b);
|
||||
}
|
||||
self.registers.insert(target_register, DvmValue::Pointer(pointer_object));
|
||||
self.registers
|
||||
.insert(target_register, DvmValue::Pointer(pointer_object));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -273,7 +678,7 @@ impl DmVirtualMachine {
|
||||
PLATFORM_CALL => {
|
||||
i += 1;
|
||||
|
||||
let symbol_name_length = get_32_le!(code, i, 0, usize);
|
||||
let symbol_name_length = next_32_le!(code, i, 0, usize);
|
||||
i += 4;
|
||||
|
||||
let symbol_name_raw = code[i..(i + symbol_name_length)].to_vec();
|
||||
@ -313,7 +718,7 @@ impl DmVirtualMachine {
|
||||
}
|
||||
INVOKE_METHOD => {
|
||||
i += 1;
|
||||
let name_length = get_32_le!(code, i, 0, usize);
|
||||
let name_length = next_32_le!(code, i, 0, usize);
|
||||
i += 4;
|
||||
let name_raw = code[i..(i + name_length)].to_vec();
|
||||
i += name_length;
|
||||
@ -394,7 +799,7 @@ mod dvm_run_tests {
|
||||
add_mov_int(&mut code, 1, 1);
|
||||
add_mov_register(&mut code, 0, 1);
|
||||
let mut vm = DmVirtualMachine::new(Vec::new());
|
||||
vm.registers.resize(2, DvmValue::Unit);
|
||||
vm.registers.resize(2, DvmValue::Uninit);
|
||||
vm.run_raw(&code);
|
||||
assert_register!(DvmValue::Int(1), vm.registers.get(0));
|
||||
}
|
||||
@ -424,6 +829,6 @@ mod dvm_run_tests {
|
||||
add_dealloc(&mut code, 0);
|
||||
let mut vm = DmVirtualMachine::new(Vec::new());
|
||||
vm.run_raw(&code);
|
||||
assert_register!(DvmValue::Unit, vm.registers.get(0));
|
||||
assert_register!(DvmValue::Uninit, vm.registers.get(0));
|
||||
}
|
||||
}
|
||||
|
@ -15,15 +15,17 @@ pub struct DmFn {
|
||||
pub short_name: String,
|
||||
pub byte_code: Vec<u8>,
|
||||
pub number_used_registers: usize,
|
||||
return_register: u8
|
||||
}
|
||||
|
||||
impl DmFn {
|
||||
pub fn new(fqn: &str, short_name: &str, byte_code: Vec<u8>, number_used_registers: usize) -> Self {
|
||||
pub fn new(fqn: &str, short_name: &str, byte_code: Vec<u8>, number_used_registers: usize, return_register: u8) -> Self {
|
||||
DmFn {
|
||||
fqn: fqn.to_string(),
|
||||
short_name: short_name.to_string(),
|
||||
byte_code,
|
||||
number_used_registers
|
||||
number_used_registers,
|
||||
return_register
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +44,10 @@ impl DmFn {
|
||||
pub fn number_used_registers(&self) -> usize {
|
||||
self.number_used_registers
|
||||
}
|
||||
|
||||
pub fn return_register(&self) -> u8 {
|
||||
self.return_register
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for DmFn {
|
||||
|
@ -45,10 +45,8 @@ pub const ALLOC_RAW_FROM: u8 = 0x0d;
|
||||
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;
|
||||
@ -159,20 +157,6 @@ pub fn add_invoke_fn(code: &mut Vec<u8>, fn_name: &str, return_register: u8, arg
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -5,22 +5,22 @@ use std::rc::Rc;
|
||||
|
||||
pub fn dm_print(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
|
||||
if args.len() != 1 {
|
||||
return DvmValue::Unit; // TODO: make exception
|
||||
return DvmValue::Uninit; // TODO: make exception
|
||||
}
|
||||
unsafe {
|
||||
print!("{}", get_string(&args[0], vm));
|
||||
}
|
||||
DvmValue::Unit
|
||||
DvmValue::Uninit
|
||||
}
|
||||
|
||||
pub fn dm_println(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
|
||||
if args.len() != 1 {
|
||||
return DvmValue::Unit;
|
||||
return DvmValue::Uninit;
|
||||
}
|
||||
unsafe {
|
||||
println!("{}", get_string(&args[0], vm));
|
||||
}
|
||||
DvmValue::Unit
|
||||
DvmValue::Uninit
|
||||
}
|
||||
|
||||
unsafe fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String {
|
||||
@ -31,7 +31,7 @@ unsafe fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String
|
||||
DvmValue::Double(d) => d.to_string(),
|
||||
DvmValue::Boolean(b) => b.to_string(),
|
||||
DvmValue::Pointer(alloc_object_rc) => convert_to_string(alloc_object_rc.clone(), vm),
|
||||
DvmValue::Unit => String::from("Unit"),
|
||||
DvmValue::Uninit => String::from("Unit"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,11 +56,16 @@ unsafe fn convert_to_string(
|
||||
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)
|
||||
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 raw_address_value =
|
||||
get_field_value(raw_address_field, &alloc_object_rc);
|
||||
|
||||
let size_field = pointer_object.implementation.get_field("size", &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 {
|
||||
@ -76,19 +81,25 @@ unsafe fn convert_to_string(
|
||||
}
|
||||
String::from_utf8(v).unwrap()
|
||||
}
|
||||
_ => panic!("Expected raw_address to be a Long.")
|
||||
_ => 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)
|
||||
_ => 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),
|
||||
_ => panic!(
|
||||
"Expected String.bytes to be a Pointer, instead found: {:?}",
|
||||
bytes_value
|
||||
),
|
||||
}
|
||||
} else {
|
||||
todo!("what happens if we don't have a String?")
|
||||
|
Loading…
Reference in New Issue
Block a user