Everything compiling and testing successfully.
This commit is contained in:
parent
d5153cc9fb
commit
21250ea695
@ -2,11 +2,10 @@ 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,
|
||||
add_alloc, add_alloc_raw_from, add_invoke_fn, add_mov_const, add_mov_register_to,
|
||||
add_mov_size_of, add_multiply, add_platform_call,
|
||||
};
|
||||
use deimos::vm::DmVirtualMachine;
|
||||
use deimos::vm::{call_fn, DvmContext, DvmState};
|
||||
use std::rc::Rc;
|
||||
|
||||
fn main() {
|
||||
@ -16,61 +15,62 @@ fn main() {
|
||||
// fn main() { println "Hello, World!" }
|
||||
|
||||
// std/unsafe/mem lib
|
||||
let mut unsafe_mem_lib = DmLib::new("std/unsafe/mem");
|
||||
let mut mem_lib = DmLib::new("std/unsafe/mem");
|
||||
|
||||
// std::unsafe::Pointer
|
||||
let unsafe_pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer");
|
||||
let unsafe_pointer_rc = Rc::new(unsafe_pointer_int);
|
||||
let pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer");
|
||||
let pointer_int_rc = Rc::new(pointer_int);
|
||||
|
||||
// std::unsafe::PointerImpl : Pointer
|
||||
let mut unsafe_pointer_impl = DmImplementation::new(
|
||||
let mut pointer_impl = DmImplementation::new(
|
||||
"std::unsafe:PointerImpl",
|
||||
"PointerImpl",
|
||||
Some(unsafe_pointer_rc.clone()),
|
||||
Some(pointer_int_rc.clone()),
|
||||
);
|
||||
|
||||
let raw_address_field = DmField::new("raw_address", DmType::Long, 0);
|
||||
let size_field = DmField::new("size", DmType::Long, 8);
|
||||
let pointer_impl_raw_address = DmField::new("raw_address", DmType::Long, 0);
|
||||
let pointer_impl_size = DmField::new("size", DmType::Long, 8);
|
||||
|
||||
// std::unsafe::Pointer::_ctor_0(
|
||||
// std::unsafe::PointerImpl::_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);
|
||||
let mut pointer_impl_ctor_0_code: Vec<u8> = Vec::new();
|
||||
add_alloc_raw_from(&mut pointer_impl_ctor_0_code, 2, 1);
|
||||
add_mov_register_to(
|
||||
&mut unsafe_pointer_ctor_0_bytecode,
|
||||
&mut pointer_impl_ctor_0_code,
|
||||
0,
|
||||
raw_address_field.data_offset() as u32,
|
||||
pointer_impl_raw_address.data_offset() as u32,
|
||||
2,
|
||||
);
|
||||
add_mov_register_to(
|
||||
&mut unsafe_pointer_ctor_0_bytecode,
|
||||
&mut pointer_impl_ctor_0_code,
|
||||
0,
|
||||
size_field.data_offset() as u32,
|
||||
pointer_impl_size.data_offset() as u32,
|
||||
1,
|
||||
);
|
||||
|
||||
let unsafe_pointer_init_fn = DmFn::new(
|
||||
let pointer_impl_ctor_0_fn = DmFn::new(
|
||||
"std::unsafe::PointerImpl::_ctor_0",
|
||||
"_ctor_0",
|
||||
unsafe_pointer_ctor_0_bytecode,
|
||||
pointer_impl_ctor_0_code,
|
||||
3,
|
||||
None,
|
||||
);
|
||||
|
||||
let unsafe_pointer_init_method = DmMethod::new(unsafe_pointer_init_fn, None);
|
||||
let pointer_impl_ctor_0_method = DmMethod::new(pointer_impl_ctor_0_fn, None);
|
||||
|
||||
unsafe_pointer_impl.fields.push(raw_address_field);
|
||||
unsafe_pointer_impl.fields.push(size_field);
|
||||
unsafe_pointer_impl
|
||||
pointer_impl.fields.push(pointer_impl_raw_address);
|
||||
pointer_impl.fields.push(pointer_impl_size);
|
||||
pointer_impl
|
||||
.methods
|
||||
.push(Rc::new(unsafe_pointer_init_method));
|
||||
.push(Rc::new(pointer_impl_ctor_0_method));
|
||||
|
||||
let unsafe_pointer_impl_rc = Rc::new(unsafe_pointer_impl);
|
||||
let unsafe_pointer_impl_rc = Rc::new(pointer_impl);
|
||||
|
||||
unsafe_mem_lib.interfaces.push(unsafe_pointer_rc.clone());
|
||||
unsafe_mem_lib
|
||||
mem_lib.interfaces.push(pointer_int_rc.clone());
|
||||
mem_lib
|
||||
.implementations
|
||||
.push(unsafe_pointer_impl_rc.clone());
|
||||
|
||||
@ -79,39 +79,44 @@ fn main() {
|
||||
// )
|
||||
// r0: size Long
|
||||
// r1: Pointer object
|
||||
// r2: Void from PointerImpl::_ctor_0
|
||||
// @return r1
|
||||
let mut alloc_fn_byte_code: Vec<u8> = Vec::new();
|
||||
let mut alloc_fn_code: Vec<u8> = Vec::new();
|
||||
add_alloc(
|
||||
&mut alloc_fn_byte_code,
|
||||
&mut alloc_fn_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",
|
||||
add_invoke_fn(
|
||||
&mut alloc_fn_code,
|
||||
"std::unsafe::PointerImpl::_ctor_0",
|
||||
2,
|
||||
&[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,
|
||||
};
|
||||
let alloc_fn = DmFn::new(
|
||||
"std::unsafe::mem::alloc",
|
||||
"alloc",
|
||||
alloc_fn_code,
|
||||
3,
|
||||
Some(1),
|
||||
);
|
||||
|
||||
unsafe_mem_lib.functions.push(Rc::new(alloc_fn));
|
||||
mem_lib.functions.push(Rc::new(alloc_fn));
|
||||
|
||||
// std/core/array lib
|
||||
let mut array_lib = DmLib::new("std/core/array");
|
||||
|
||||
// std::core::Array
|
||||
let core_array_int = DmInterface::new("std::core::Array", "Array");
|
||||
let core_array_int_rc = Rc::new(core_array_int);
|
||||
let array_int = DmInterface::new("std::core::Array", "Array");
|
||||
let array_int_rc = Rc::new(array_int);
|
||||
|
||||
// std::core::ArrayImpl
|
||||
let mut core_array_impl = DmImplementation::new(
|
||||
let mut array_impl = DmImplementation::new(
|
||||
"std::core::ArrayImpl",
|
||||
"ArrayImpl",
|
||||
Some(core_array_int_rc.clone()),
|
||||
Some(array_int_rc.clone()),
|
||||
);
|
||||
|
||||
let array_impl_pointer_fld = DmField::new("pointer", DmType::Pointer, 0);
|
||||
@ -153,16 +158,18 @@ fn main() {
|
||||
"_ctor_0",
|
||||
array_impl_ctor_0_bytecode,
|
||||
6,
|
||||
None,
|
||||
);
|
||||
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));
|
||||
array_impl.methods.push(Rc::new(array_impl_ctor_0_method));
|
||||
|
||||
// Add Array and ArrayImpl to array lib
|
||||
array_lib.interfaces.push(array_int_rc.clone());
|
||||
array_lib.implementations.push(Rc::new(array_impl));
|
||||
|
||||
// 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 mut string_lib = DmLib::new("std/core/string");
|
||||
let mut string_impl = DmImplementation::new("std::core::String", "String", None);
|
||||
|
||||
let bytes_field = DmField::new("bytes", DmType::Pointer, 0);
|
||||
|
||||
@ -170,31 +177,31 @@ fn main() {
|
||||
// r0: self
|
||||
// r1: DvmPointer to Array<Byte>
|
||||
// )
|
||||
let mut core_string_ctor_0_bytecode: Vec<u8> = Vec::new();
|
||||
let mut string_ctor_0_bytecode: Vec<u8> = Vec::new();
|
||||
add_mov_register_to(
|
||||
&mut core_string_ctor_0_bytecode,
|
||||
&mut 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 string_ctor_0_fn = DmFn::new(
|
||||
"std::core::String::_ctor_0",
|
||||
"_ctor_0",
|
||||
string_ctor_0_bytecode,
|
||||
2,
|
||||
None,
|
||||
);
|
||||
|
||||
let core_string_ctor_0_method = DmMethod::new(core_string_ctor_0_fn, None);
|
||||
let string_ctor_0_method = DmMethod::new(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();
|
||||
string_impl.fields.push(bytes_field);
|
||||
string_impl.methods.push(Rc::new(string_ctor_0_method));
|
||||
let core_string_impl_size = string_impl.size_in_bytes();
|
||||
|
||||
core_string_lib
|
||||
.implementations
|
||||
.push(Rc::new(core_string_impl));
|
||||
string_lib.implementations.push(Rc::new(string_impl));
|
||||
|
||||
// greeting lib
|
||||
let mut greeting_lib = DmLib::new("greeting");
|
||||
greeting_lib
|
||||
.constants
|
||||
@ -202,9 +209,9 @@ fn main() {
|
||||
|
||||
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
|
||||
// 1. Move constant: r0 receives DvmValue::Pointer to ArrayImpl<Byte>
|
||||
// 2. Allocate for std::core::StringImpl into r1
|
||||
// 3. Call StringImpl::_ctor_0(r0) -> r2
|
||||
// 4. Platform call std::core::println(r1) -> r3
|
||||
add_alloc(
|
||||
&mut main_byte_code,
|
||||
@ -213,21 +220,22 @@ fn main() {
|
||||
"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]);
|
||||
add_invoke_fn(
|
||||
&mut main_byte_code,
|
||||
"std::core::StringImpl::_ctor_0",
|
||||
2,
|
||||
&[0, 1],
|
||||
);
|
||||
add_platform_call(&mut main_byte_code, "std::core::println", 3, 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,
|
||||
};
|
||||
let main_dm_fn = DmFn::new("main", "main", main_byte_code, 2, None);
|
||||
|
||||
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());
|
||||
let mut state = DvmState::new();
|
||||
let mut context = DvmContext::new();
|
||||
context.load_functions(&vec![greeting_lib, string_lib, mem_lib]);
|
||||
|
||||
let main_fn = context.fn_by_fqn("main").unwrap();
|
||||
call_fn(&mut state, &context, &main_fn, vec![]);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ pub enum DvmValue {
|
||||
Boolean(bool),
|
||||
Pointer(Rc<DmAllocObject>),
|
||||
Uninit,
|
||||
Void,
|
||||
}
|
||||
|
||||
impl DvmValue {
|
||||
|
571
src/vm/mod.rs
571
src/vm/mod.rs
@ -11,14 +11,13 @@ use crate::vm::dvm_value::DvmValue;
|
||||
use crate::vm::lib::{DmConstant, DmLib};
|
||||
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, dealloc, Layout};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use util::{get_32_le, get_64_le};
|
||||
|
||||
pub type PlatformFunction = fn(args: Vec<DvmValue>, &mut DmVirtualMachine) -> DvmValue;
|
||||
pub type PlatformFunction =
|
||||
fn(args: Vec<DvmValue>, state: &mut DvmState, context: &DvmContext) -> DvmValue;
|
||||
|
||||
enum CallFrame {
|
||||
PlatformCall(CallFrameInfo),
|
||||
@ -29,17 +28,6 @@ struct CallFrameInfo {
|
||||
fn_fqn: String,
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
pub struct DmVirtualMachine {
|
||||
libs: Vec<DmLib>,
|
||||
functions: HashMap<String, Rc<DmFn>>,
|
||||
platform_functions: HashMap<String, PlatformFunction>,
|
||||
ip: usize,
|
||||
call_stack: Vec<CallFrame>,
|
||||
registers: Vec<DvmValue>,
|
||||
register_state_stack: Vec<Vec<DvmValue>>,
|
||||
}
|
||||
|
||||
pub struct DvmContext {
|
||||
libs: Vec<DmLib>,
|
||||
functions: HashMap<String, Rc<DmFn>>,
|
||||
@ -55,6 +43,35 @@ impl DvmContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_functions(&mut self, libs: &Vec<DmLib>) {
|
||||
for lib in libs {
|
||||
for lib_fn in &lib.functions {
|
||||
self.functions
|
||||
.insert(lib_fn.fqn().to_string(), lib_fn.clone());
|
||||
}
|
||||
for interface_function in lib
|
||||
.interfaces
|
||||
.iter()
|
||||
.flat_map(|interface| interface.get_functions())
|
||||
{
|
||||
self.functions.insert(
|
||||
interface_function.fqn().to_string(),
|
||||
interface_function.clone(),
|
||||
);
|
||||
}
|
||||
for implementation_function in lib
|
||||
.implementations
|
||||
.iter()
|
||||
.flat_map(|implementation| &implementation.functions)
|
||||
{
|
||||
self.functions.insert(
|
||||
implementation_function.fqn().to_string(),
|
||||
implementation_function.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fn_by_fqn(&self, fqn: &str) -> Option<Rc<DmFn>> {
|
||||
self.functions.get(fqn).cloned()
|
||||
}
|
||||
@ -80,40 +97,15 @@ impl DvmState {
|
||||
}
|
||||
}
|
||||
|
||||
fn load_functions(destination: &mut HashMap<String, Rc<DmFn>>, libs: &Vec<DmLib>) {
|
||||
for lib in libs {
|
||||
for lib_fn in &lib.functions {
|
||||
destination.insert(lib_fn.fqn.clone(), lib_fn.clone());
|
||||
}
|
||||
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 lib
|
||||
.implementations
|
||||
.iter()
|
||||
.flat_map(|implementation| &implementation.functions)
|
||||
{
|
||||
destination.insert(
|
||||
implementation_function.fqn.clone(),
|
||||
implementation_function.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_fn(
|
||||
state: &mut DvmState,
|
||||
context: &DvmContext,
|
||||
dm_fn: &DmFn,
|
||||
args: Vec<DvmValue>,
|
||||
) -> Option<DvmValue> {
|
||||
) -> DvmValue {
|
||||
// save current state
|
||||
state.call_stack.push(CallFrame::DeimosCall(CallFrameInfo {
|
||||
fn_fqn: dm_fn.fqn.clone(),
|
||||
fn_fqn: dm_fn.fqn().to_string(),
|
||||
}));
|
||||
state.register_state_stack.push(state.registers.clone());
|
||||
|
||||
@ -131,20 +123,22 @@ pub fn call_fn(
|
||||
}
|
||||
|
||||
// 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());
|
||||
run_byte_code(state, context, &dm_fn.byte_code());
|
||||
|
||||
// restore state
|
||||
state.registers = state.register_state_stack.pop().unwrap();
|
||||
state.call_stack.pop();
|
||||
|
||||
// return result
|
||||
return_value
|
||||
// get return value
|
||||
if let Some(return_register) = dm_fn.return_register() {
|
||||
state
|
||||
.registers
|
||||
.get(return_register as usize)
|
||||
.map(|m| m.clone())
|
||||
.unwrap()
|
||||
} else {
|
||||
DvmValue::Void
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! next_8 {
|
||||
@ -175,6 +169,19 @@ macro_rules! next_64_le {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_array_u8 {
|
||||
( $iter: expr ) => {{
|
||||
let arr_length = next_8!($iter, u8);
|
||||
let mut arr = Vec::with_capacity(arr_length as usize);
|
||||
let mut i = 0;
|
||||
while i < arr_length {
|
||||
arr.push(next_8!($iter, u8));
|
||||
i += 1;
|
||||
}
|
||||
arr
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! read_string {
|
||||
( $iter: expr ) => {{
|
||||
let str_length = next_32_le!($iter, usize);
|
||||
@ -262,9 +269,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
|
||||
}
|
||||
DEALLOC => {
|
||||
let target_register = next_8!(iter, usize);
|
||||
let dm_alloc_object = state.registers
|
||||
.remove(target_register)
|
||||
.expect_pointer();
|
||||
let dm_alloc_object = state.registers.remove(target_register).expect_pointer();
|
||||
drop(dm_alloc_object); // explicit
|
||||
}
|
||||
MOV_INT_TO => {
|
||||
@ -326,6 +331,9 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
|
||||
DvmValue::Uninit => {
|
||||
panic!("Cannot move DvmValue::Uninit to object.")
|
||||
}
|
||||
DvmValue::Void => {
|
||||
panic!("Cannot move DvmValue::Void to object.")
|
||||
}
|
||||
}
|
||||
}
|
||||
MOV_CONST => {
|
||||
@ -429,29 +437,101 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
|
||||
);
|
||||
}
|
||||
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!()
|
||||
// of the source register. The address is stored in the target register as a
|
||||
// DvmValue::Long.
|
||||
let target_register = next_8!(iter, usize);
|
||||
let source_register = next_8!(iter, usize);
|
||||
let number_of_bytes =
|
||||
state.registers.get(source_register).unwrap().expect_long() as usize;
|
||||
let layout = Layout::from_size_align(number_of_bytes, 0).unwrap();
|
||||
let ptr = unsafe { alloc(layout) };
|
||||
state
|
||||
.registers
|
||||
.insert(target_register, DvmValue::Long(ptr as i64))
|
||||
}
|
||||
DEALLOC_RAW => {
|
||||
// Deallocates a raw number of bytes at an address, with the number of bytes
|
||||
// determined by the value in the source register, and the address stored in the
|
||||
// target register.
|
||||
let target_register = next_8!(iter, usize);
|
||||
let source_register = next_8!(iter, usize);
|
||||
let number_of_bytes =
|
||||
state.registers.get(source_register).unwrap().expect_long() as usize;
|
||||
|
||||
let layout = Layout::from_size_align(number_of_bytes, 0).unwrap();
|
||||
let ptr =
|
||||
state.registers.get(target_register).unwrap().expect_long() as usize as *mut u8;
|
||||
unsafe {
|
||||
dealloc(ptr, layout);
|
||||
}
|
||||
state.registers.insert(target_register, DvmValue::Uninit);
|
||||
}
|
||||
PLATFORM_CALL => {
|
||||
todo!()
|
||||
// Calls a platform function. The result of the platform call is stored in the
|
||||
// specified return register.
|
||||
let symbol_name = read_string!(iter);
|
||||
let return_register = next_8!(iter, usize);
|
||||
let arg_registers = read_array_u8!(iter);
|
||||
|
||||
let mut args = Vec::with_capacity(arg_registers.len());
|
||||
for arg_register in arg_registers {
|
||||
let value = state.registers.get(arg_register as usize).unwrap();
|
||||
args.push(value.clone());
|
||||
}
|
||||
|
||||
let platform_function = context
|
||||
.platform_functions
|
||||
.get(&symbol_name)
|
||||
.unwrap()
|
||||
.clone();
|
||||
state
|
||||
.call_stack
|
||||
.push(CallFrame::PlatformCall(CallFrameInfo {
|
||||
fn_fqn: symbol_name,
|
||||
}));
|
||||
let call_result = platform_function(args, state, context);
|
||||
state.registers.insert(return_register, call_result);
|
||||
state.call_stack.pop();
|
||||
}
|
||||
INVOKE_FN => {
|
||||
todo!()
|
||||
let symbol_name = read_string!(iter);
|
||||
let return_register = next_8!(iter, usize);
|
||||
let arg_registers = read_array_u8!(iter);
|
||||
|
||||
let mut args = Vec::with_capacity(arg_registers.len());
|
||||
for arg_register in arg_registers {
|
||||
let value = state.registers.get(arg_register as usize).unwrap();
|
||||
args.push(value.clone());
|
||||
}
|
||||
|
||||
let dm_fn = context.functions.get(&symbol_name).unwrap();
|
||||
let call_result = call_fn(state, context, dm_fn, args);
|
||||
state.registers.insert(return_register, call_result);
|
||||
}
|
||||
INVOKE_VIRTUAL => {
|
||||
todo!()
|
||||
let symbol_name = read_string!(iter);
|
||||
let return_register = next_8!(iter, usize);
|
||||
let arg_registers = read_array_u8!(iter);
|
||||
|
||||
let mut args = Vec::with_capacity(arg_registers.len());
|
||||
for arg_register in arg_registers {
|
||||
let value = state.registers.get(arg_register as usize).unwrap();
|
||||
args.push(value.clone());
|
||||
}
|
||||
|
||||
let self_obj = args.get(0).unwrap().expect_pointer();
|
||||
let method = self_obj
|
||||
.implementation
|
||||
.get_method(&symbol_name, &self_obj)
|
||||
.expect(&format!("Could not find method: {}", symbol_name));
|
||||
let dm_fn = method.dm_fn();
|
||||
|
||||
let call_result = call_fn(state, context, dm_fn, args);
|
||||
state.registers.insert(return_register, call_result);
|
||||
}
|
||||
INVOKE_DYNAMIC => {
|
||||
todo!()
|
||||
}
|
||||
RETURN_REGISTER => {
|
||||
todo!()
|
||||
unimplemented!("INVOKE_DYNAMIC is not yet supported and may never be.")
|
||||
}
|
||||
MOV_SIZE_OF => {
|
||||
todo!()
|
||||
@ -466,331 +546,48 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
|
||||
}
|
||||
}
|
||||
|
||||
impl DmVirtualMachine {
|
||||
pub fn new(libs: Vec<DmLib>) -> DmVirtualMachine {
|
||||
let mut vm = DmVirtualMachine {
|
||||
libs: libs,
|
||||
functions: HashMap::new(),
|
||||
platform_functions: init_platform_functions(),
|
||||
ip: 0,
|
||||
registers: Vec::new(),
|
||||
call_stack: Vec::new(),
|
||||
register_state_stack: Vec::new(),
|
||||
};
|
||||
load_functions(&mut vm.functions, &vm.libs);
|
||||
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 {
|
||||
return_address: self.ip,
|
||||
}));
|
||||
self.register_state_stack.push(self.registers.clone());
|
||||
|
||||
// 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::Uninit);
|
||||
}
|
||||
|
||||
// push args
|
||||
for i in 0..args.len() {
|
||||
self.registers.insert(i, args[i].clone());
|
||||
}
|
||||
|
||||
// run the byte code
|
||||
self.run_raw(&dm_function.byte_code);
|
||||
|
||||
// restore state
|
||||
self.registers = self.register_state_stack.pop().unwrap();
|
||||
if let CallFrame::DeimosCall(deimos_call_frame) = self.call_stack.pop().unwrap() {
|
||||
self.ip = deimos_call_frame.return_address;
|
||||
}
|
||||
|
||||
// return result
|
||||
self.registers.get(0).map(|x| x.clone())
|
||||
}
|
||||
|
||||
pub fn run_raw(&mut self, code: &Vec<u8>) {
|
||||
let mut i = 0;
|
||||
while i < code.len() {
|
||||
let op_code = code[i];
|
||||
println!("op_code: {:#04x}", op_code);
|
||||
match code[i] {
|
||||
MOV_INT => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let operand = next_32_le!(code, i, 2, u32);
|
||||
self.registers
|
||||
.insert(target_register, DvmValue::Int(operand as i32));
|
||||
i += 6;
|
||||
}
|
||||
MOV_LONG => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let operand = get_64_le!(code, i, 2, u64);
|
||||
self.registers
|
||||
.insert(target_register, DvmValue::Long(operand as i64));
|
||||
i += 10;
|
||||
}
|
||||
MOV_DOUBLE => {
|
||||
unimplemented!();
|
||||
}
|
||||
MOV_REGISTER => {
|
||||
let target_register = code[i + 1] as usize;
|
||||
let source_register = code[i + 2] as usize;
|
||||
let source_value = self.registers.get(source_register).unwrap();
|
||||
self.registers.insert(target_register, source_value.clone());
|
||||
i += 3;
|
||||
}
|
||||
ALLOC => {
|
||||
i += 1;
|
||||
let target_register = code[i] as usize;
|
||||
i += 1;
|
||||
let alloc_size = next_32_le!(code, i, 0, usize);
|
||||
i += 4;
|
||||
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();
|
||||
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 => {
|
||||
todo!()
|
||||
}
|
||||
MOV_INT_TO => {
|
||||
todo!()
|
||||
}
|
||||
MOV_REGISTER_TO => {
|
||||
i += 1;
|
||||
let target_register = code[i] as usize;
|
||||
i += 1;
|
||||
let offset = next_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 = 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 = next_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 => {
|
||||
i += 1;
|
||||
|
||||
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();
|
||||
i += symbol_name_length;
|
||||
|
||||
let symbol_name = String::from_utf8(symbol_name_raw).unwrap();
|
||||
|
||||
let return_register = code[i + 1] as usize;
|
||||
i += 1;
|
||||
|
||||
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 mut args = Vec::new();
|
||||
for arg_register in arg_registers {
|
||||
let register_value = self.registers.get(arg_register as usize).unwrap();
|
||||
args.push(register_value.clone());
|
||||
}
|
||||
|
||||
let platform_function_result = self.platform_functions.get(&symbol_name);
|
||||
if platform_function_result.is_none() {
|
||||
panic!("Unknown platform function {}", symbol_name);
|
||||
}
|
||||
let platform_function = platform_function_result.unwrap();
|
||||
|
||||
let call_result = platform_function(args, self);
|
||||
self.registers.insert(return_register, call_result);
|
||||
}
|
||||
INVOKE_FN => {
|
||||
unimplemented!()
|
||||
}
|
||||
INVOKE_VIRTUAL => {
|
||||
unimplemented!();
|
||||
}
|
||||
INVOKE_METHOD => {
|
||||
i += 1;
|
||||
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;
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod dvm_run_tests {
|
||||
mod run_code_tests {
|
||||
use super::*;
|
||||
|
||||
macro_rules! assert_register {
|
||||
( $expected: expr, $register: expr ) => {
|
||||
assert_eq!($expected, $register.unwrap().clone());
|
||||
( $expected: expr, $state: expr, $register_number: expr ) => {
|
||||
assert_eq!(
|
||||
$expected,
|
||||
$state.registers.get($register_number).unwrap().clone()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
fn setup() -> (DvmState, DvmContext) {
|
||||
(DvmState::new(), DvmContext::new())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mov_1_as_int() {
|
||||
let mut code = Vec::new();
|
||||
add_mov_int(&mut code, 0, 1);
|
||||
let mut vm = DmVirtualMachine::new(Vec::new());
|
||||
vm.run_raw(&code);
|
||||
assert_register!(DvmValue::Int(1), vm.registers.get(0));
|
||||
let (mut state, context) = setup();
|
||||
run_byte_code(&mut state, &context, &code);
|
||||
assert_register!(DvmValue::Int(1), state, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_65535_as_int() {
|
||||
let mut code = Vec::new();
|
||||
add_mov_int(&mut code, 0, 0xffff);
|
||||
let mut vm = DmVirtualMachine::new(Vec::new());
|
||||
vm.run_raw(&code);
|
||||
assert_register!(DvmValue::Int(0xffff), vm.registers.get(0));
|
||||
let (mut state, context) = setup();
|
||||
run_byte_code(&mut state, &context, &code);
|
||||
assert_register!(DvmValue::Int(0xffff), state, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_int_max_as_int() {
|
||||
let mut code = Vec::new();
|
||||
add_mov_int(&mut code, 0, 0x0fff_ffff);
|
||||
let mut vm = DmVirtualMachine::new(Vec::new());
|
||||
vm.run_raw(&code);
|
||||
assert_register!(DvmValue::Int(0x0fff_ffff), vm.registers.get(0));
|
||||
let (mut state, context) = setup();
|
||||
run_byte_code(&mut state, &context, &code);
|
||||
assert_register!(DvmValue::Int(0x0fff_ffff), state, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -798,37 +595,9 @@ mod dvm_run_tests {
|
||||
let mut code = Vec::new();
|
||||
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::Uninit);
|
||||
vm.run_raw(&code);
|
||||
assert_register!(DvmValue::Int(1), vm.registers.get(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn mov_int_to_register_as_address() {
|
||||
let mut code = Vec::new();
|
||||
add_alloc(&mut code, 0, 4);
|
||||
add_mov_int_to(&mut code, 0, 0, 0xff);
|
||||
let mut vm = DmVirtualMachine::new(Vec::new());
|
||||
vm.run_raw(&code);
|
||||
let actual = vm.registers.get(0).unwrap().clone();
|
||||
match actual {
|
||||
DvmValue::Pointer(value_box) => {
|
||||
assert_eq!(DvmValue::Int(0xff), *value_box);
|
||||
}
|
||||
_ => panic!("Target register is not a pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn alloc_and_dealloc_expect_register_cleared() {
|
||||
let mut code = Vec::new();
|
||||
add_alloc(&mut code, 0, 4);
|
||||
add_dealloc(&mut code, 0);
|
||||
let mut vm = DmVirtualMachine::new(Vec::new());
|
||||
vm.run_raw(&code);
|
||||
assert_register!(DvmValue::Uninit, vm.registers.get(0));
|
||||
let (mut state, context) = setup();
|
||||
state.registers.resize(2, DvmValue::Uninit);
|
||||
run_byte_code(&mut state, &context, &code);
|
||||
assert_register!(DvmValue::Int(1), state, 0);
|
||||
}
|
||||
}
|
||||
|
@ -11,21 +11,27 @@ pub enum DmObjectType {
|
||||
|
||||
#[derive(Debug, Eq)]
|
||||
pub struct DmFn {
|
||||
pub fqn: String,
|
||||
pub short_name: String,
|
||||
pub byte_code: Vec<u8>,
|
||||
pub number_used_registers: usize,
|
||||
return_register: u8
|
||||
fqn: String,
|
||||
short_name: String,
|
||||
byte_code: Vec<u8>,
|
||||
number_used_registers: usize,
|
||||
return_register: Option<u8>,
|
||||
}
|
||||
|
||||
impl DmFn {
|
||||
pub fn new(fqn: &str, short_name: &str, byte_code: Vec<u8>, number_used_registers: usize, return_register: u8) -> Self {
|
||||
pub fn new(
|
||||
fqn: &str,
|
||||
short_name: &str,
|
||||
byte_code: Vec<u8>,
|
||||
number_used_registers: usize,
|
||||
return_register: Option<u8>,
|
||||
) -> Self {
|
||||
DmFn {
|
||||
fqn: fqn.to_string(),
|
||||
short_name: short_name.to_string(),
|
||||
byte_code,
|
||||
number_used_registers,
|
||||
return_register
|
||||
return_register,
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +51,7 @@ impl DmFn {
|
||||
self.number_used_registers
|
||||
}
|
||||
|
||||
pub fn return_register(&self) -> u8 {
|
||||
pub fn return_register(&self) -> Option<u8> {
|
||||
self.return_register
|
||||
}
|
||||
}
|
||||
@ -75,6 +81,10 @@ impl DmMethod {
|
||||
implements,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dm_fn(&self) -> &DmFn {
|
||||
&self.dm_fn
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq)]
|
||||
@ -243,7 +253,7 @@ impl DmField {
|
||||
DmField {
|
||||
name: name.to_string(),
|
||||
dm_type,
|
||||
data_offset
|
||||
data_offset,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,16 +39,14 @@ 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 ALLOC_RAW: u8 = 0x0d;
|
||||
pub const DEALLOC_RAW: u8 = 0x0e;
|
||||
|
||||
pub const PLATFORM_CALL: u8 = 0x10;
|
||||
pub const INVOKE_FN: u8 = 0x11;
|
||||
pub const INVOKE_VIRTUAL: u8 = 0x12;
|
||||
pub const INVOKE_DYNAMIC: u8 = 0x14;
|
||||
|
||||
pub const RETURN_REGISTER: u8 = 0x21;
|
||||
|
||||
pub const MOV_SIZE_OF: u8 = 0x30;
|
||||
|
||||
pub const MULTIPLY: u8 = 0x40;
|
||||
@ -85,14 +83,8 @@ pub fn add_alloc(code: &mut Vec<u8>, register: u8, size: u32, implementation_nam
|
||||
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(ALLOC_RAW);
|
||||
code.push(target_register);
|
||||
push_number!(code, source_register);
|
||||
}
|
||||
@ -157,11 +149,6 @@ pub fn add_invoke_fn(code: &mut Vec<u8>, fn_name: &str, return_register: u8, arg
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -1,107 +1,84 @@
|
||||
use crate::vm::dvm_value::DvmValue;
|
||||
use crate::vm::mem::{get_field_value, DmAllocObject};
|
||||
use crate::vm::DmVirtualMachine;
|
||||
use crate::vm::{DvmContext, DvmState};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn dm_print(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
|
||||
pub fn dm_print(args: Vec<DvmValue>, _state: &mut DvmState, _context: &DvmContext) -> DvmValue {
|
||||
if args.len() != 1 {
|
||||
return DvmValue::Uninit; // TODO: make exception
|
||||
return DvmValue::Void; // TODO: make exception
|
||||
}
|
||||
unsafe {
|
||||
print!("{}", get_string(&args[0], vm));
|
||||
print!("{}", get_string(&args[0]));
|
||||
}
|
||||
DvmValue::Uninit
|
||||
DvmValue::Void
|
||||
}
|
||||
|
||||
pub fn dm_println(args: Vec<DvmValue>, vm: &mut DmVirtualMachine) -> DvmValue {
|
||||
pub fn dm_println(args: Vec<DvmValue>, _state: &mut DvmState, _context: &DvmContext) -> DvmValue {
|
||||
if args.len() != 1 {
|
||||
return DvmValue::Uninit;
|
||||
}
|
||||
unsafe {
|
||||
println!("{}", get_string(&args[0], vm));
|
||||
println!("{}", get_string(&args[0]));
|
||||
}
|
||||
DvmValue::Uninit
|
||||
DvmValue::Void
|
||||
}
|
||||
|
||||
unsafe fn get_string(dvm_value: &DvmValue, vm: &mut DmVirtualMachine) -> String {
|
||||
unsafe fn get_string(dvm_value: &DvmValue) -> String {
|
||||
match dvm_value {
|
||||
DvmValue::Byte(b) => b.to_string(),
|
||||
DvmValue::Int(i) => i.to_string(),
|
||||
DvmValue::Long(l) => l.to_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::Uninit => String::from("Unit"),
|
||||
DvmValue::Pointer(object) => convert_to_string(object.clone()),
|
||||
DvmValue::Uninit => String::from("Uninit"),
|
||||
DvmValue::Void => String::from("Void"),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn convert_to_string(
|
||||
alloc_object_rc: Rc<DmAllocObject>,
|
||||
vm: &mut DmVirtualMachine,
|
||||
) -> String {
|
||||
fn convert_to_string(alloc_object_rc: Rc<DmAllocObject>) -> String {
|
||||
if alloc_object_rc.implementation.fqn == "std::core::String" {
|
||||
let bytes_field = alloc_object_rc
|
||||
.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
|
||||
),
|
||||
}
|
||||
extract_string_from_string(alloc_object_rc.clone())
|
||||
} else {
|
||||
todo!("what happens if we don't have a String?")
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_string_from_string(string_object: Rc<DmAllocObject>) -> String {
|
||||
let bytes_field = string_object
|
||||
.implementation
|
||||
.get_field("bytes", &string_object)
|
||||
.expect("Could not get String.bytes field.");
|
||||
let bytes_object = unsafe { get_field_value(&bytes_field, &string_object) }.expect_pointer();
|
||||
if bytes_object.implementation.fqn != "std::core::ArrayImpl" {
|
||||
panic!("String.bytes field is not a std::core::ArrayImpl");
|
||||
}
|
||||
|
||||
let pointer_field = bytes_object
|
||||
.implementation
|
||||
.get_field("pointer", &bytes_object)
|
||||
.expect("Could not get ArrayImpl.pointer field.");
|
||||
let pointer_object = unsafe { get_field_value(&pointer_field, &bytes_object) }.expect_pointer();
|
||||
if pointer_object.implementation.fqn != "std::unsafe::PointerImpl" {
|
||||
panic!("ArrayImpl.pointer is not a 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 = unsafe { get_field_value(&raw_address_field, &pointer_object) }.expect_long();
|
||||
|
||||
let size_field = pointer_object
|
||||
.implementation
|
||||
.get_field("size", &pointer_object)
|
||||
.expect("Could not get PointerImpl.size field.");
|
||||
let size = unsafe { get_field_value(&size_field, &pointer_object) }.expect_long();
|
||||
|
||||
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(unsafe { raw_bytes_pointer.offset(i).read() });
|
||||
}
|
||||
String::from_utf8(v).unwrap()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user