Successfully printed greeting!

This commit is contained in:
Jesse Brault 2024-12-26 23:05:59 -06:00
parent b7588b8787
commit e7a7cba26d
15 changed files with 304 additions and 436 deletions

View File

@ -1,8 +1,5 @@
ns std::core
use std::unsafe::Pointer
use std::unsafe::mem::{alloc, pointer_of)
pub int Array<T> : Monad + Default + Empty {
const default = array::empty<Self>
const empty = array::empty<Self>
@ -10,42 +7,12 @@ pub int Array<T> : Monad + Default + Empty {
length: Int
}
impl ArrayImpl<T> : Array<T> {
fld pointer: Pointer
fld length: Int
pub unsafe ctor(length: Int) {
self.pointer = alloc(length * T::size())
self.length = length
}
pub ctor(pointer: Pointer, length: Int) {
self.pointer = pointer
self.length = length
}
pub unsafe fn set(index: Int, item: Pointer) {
pointer.offset(index * T::size()).write(item.read())
}
}
pub mod array {
// Usage:
// let int_array = array::of(1, 2, 3)
// assert_eq(3, int_array.length)
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<T>(ts: ...T): Array<T>
pub extern fn of_length<T>(length: Int, init_value: T): Array<T>

View File

@ -1,14 +1 @@
ns std::unsafe
pub int Pointer
// Contains two fields:
// fld raw_address: Long
// fld size: Long
decl impl PointerImpl(size: Long) : Pointer
pub mod mem {
pub fn alloc(size: Long): Pointer = PointerImpl(size)
}

View File

@ -2,9 +2,9 @@ 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_mov_const, add_mov_register_to,
add_mov_size_of, add_multiply, add_platform_call,
add_alloc, add_invoke_fn, add_mov_const, add_mov_register_to, add_platform_call,
};
use deimos::vm::platform::init_platform_functions;
use deimos::vm::{call_fn, DvmContext, DvmState};
use std::rc::Rc;
@ -14,95 +14,6 @@ fn main() {
// - call the main fn
// fn main() { println "Hello, World!" }
// std/unsafe/mem lib
let mut mem_lib = DmLib::new("std/unsafe/mem");
// std::unsafe::Pointer
let pointer_int = DmInterface::new("std::unsafe::Pointer", "Pointer");
let pointer_int_rc = Rc::new(pointer_int);
// std::unsafe::PointerImpl : Pointer
let mut pointer_impl = DmImplementation::new(
"std::unsafe:PointerImpl",
"PointerImpl",
Some(pointer_int_rc.clone()),
);
let pointer_impl_raw_address = DmField::new("raw_address", DmType::Long, 0);
let pointer_impl_size = DmField::new("size", DmType::Long, 8);
// std::unsafe::PointerImpl::_ctor_0(
// r0: self
// r1: size Long
// )
// r2: raw_address Long
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 pointer_impl_ctor_0_code,
0,
pointer_impl_raw_address.data_offset() as u32,
2,
);
add_mov_register_to(
&mut pointer_impl_ctor_0_code,
0,
pointer_impl_size.data_offset() as u32,
1,
);
let pointer_impl_ctor_0_fn = DmFn::new(
"std::unsafe::PointerImpl::_ctor_0",
"_ctor_0",
pointer_impl_ctor_0_code,
3,
None,
);
let pointer_impl_ctor_0_method = DmMethod::new(pointer_impl_ctor_0_fn, None);
pointer_impl.fields.push(pointer_impl_raw_address);
pointer_impl.fields.push(pointer_impl_size);
pointer_impl
.methods
.push(Rc::new(pointer_impl_ctor_0_method));
let unsafe_pointer_impl_rc = Rc::new(pointer_impl);
mem_lib.interfaces.push(pointer_int_rc.clone());
mem_lib.implementations.push(unsafe_pointer_impl_rc.clone());
// std::unsafe::alloc(
// r0: size Long
// )
// r0: size Long
// r1: Pointer object
// r2: Void from PointerImpl::_ctor_0
// @return r1
let mut alloc_fn_code: Vec<u8> = Vec::new();
add_alloc(
&mut alloc_fn_code,
1,
unsafe_pointer_impl_rc.size_in_bytes() as u32,
"std::unsafe::PointerImpl",
);
add_invoke_fn(
&mut alloc_fn_code,
"std::unsafe::PointerImpl::_ctor_0",
2,
&[1u8, 0u8],
);
let alloc_fn = DmFn::new(
"std::unsafe::mem::alloc",
"alloc",
alloc_fn_code,
3,
Some(1),
);
mem_lib.functions.push(Rc::new(alloc_fn));
// std/core/array lib
let mut array_lib = DmLib::new("std/core/array");
@ -117,45 +28,31 @@ fn main() {
Some(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);
let array_impl_ptr_address_fld = DmField::new("ptr_address", DmType::USize, 0);
let array_impl_ptr_size_fld = DmField::new("ptr_size", DmType::USize, 8);
let array_impl_length_fld = DmField::new("length", DmType::Long, 16);
// std::core::Array::_ctor_0(
array_impl.fields.push(array_impl_ptr_address_fld);
array_impl.fields.push(array_impl_ptr_size_fld);
array_impl.fields.push(array_impl_length_fld);
// std::core::ArrayImpl::_ctor_0(
// r0: self
// r1: TypeRef element_type
// r2: Int length
// r1: USize ptr_address
// r2: USize ptr_size
// r3: Long 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,
);
add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 0, 1);
add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 8, 2);
add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 16, 3);
let array_impl_ctor_0_fn = DmFn::new(
"std::core::ArrayImpl::_ctor_0",
"_ctor_0",
array_impl_ctor_0_bytecode,
6,
4,
None,
);
let array_impl_ctor_0_method = DmMethod::new(array_impl_ctor_0_fn, None);
@ -163,7 +60,8 @@ fn main() {
// Add Array and ArrayImpl to array lib
array_lib.interfaces.push(array_int_rc.clone());
array_lib.implementations.push(Rc::new(array_impl));
let array_impl_rc = Rc::new(array_impl);
array_lib.implementations.push(array_impl_rc.clone());
// std::core::String
let mut string_lib = DmLib::new("std/core/string");
@ -172,19 +70,15 @@ fn main() {
let mut string_impl = DmImplementation::new("std::core::StringImpl", "StringImpl", None);
let bytes_field = DmField::new("bytes", DmType::Pointer, 0);
let bytes_field = DmField::new("bytes", DmType::Object, 0);
string_impl.fields.push(bytes_field);
// std::core::String::_ctor_0(
// r0: self
// r1: DvmPointer to Array<Byte>
// r1: Array<Byte> bytes
// )
let mut string_ctor_0_bytecode: Vec<u8> = Vec::new();
add_mov_register_to(
&mut string_ctor_0_bytecode,
0,
bytes_field.data_offset() as u32,
1,
);
add_mov_register_to(&mut string_ctor_0_bytecode, 0, 0, 1);
let string_ctor_0_fn = DmFn::new(
"std::core::StringImpl::_ctor_0",
@ -196,7 +90,6 @@ fn main() {
let string_ctor_0_method = DmMethod::new(string_ctor_0_fn, None);
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();
@ -207,41 +100,62 @@ fn main() {
let mut greeting_lib = DmLib::new("greeting");
greeting_lib
.constants
.push(DmConstant::String("Hello, World!".to_string()));
.push(DmConstant::String("Hello, Jeanna!".to_string()));
let mut main_byte_code = Vec::new();
// 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
// Move greeting
// r0: greeting address
// r1: greeting size
add_mov_const(&mut main_byte_code, 0, 1, "greeting", 0);
// Alloc Array<Byte> greeting bytes
add_alloc(
&mut main_byte_code,
0,
2,
array_impl_rc.size_in_bytes() as u32,
"std::core::ArrayImpl",
);
// Call ArrayImpl(ptr_address, ptr_size, length)
add_invoke_fn(
&mut main_byte_code,
"std::core::ArrayImpl::_ctor_0",
3,
&[2, 0, 1, 1],
);
// Alloc StringImpl greeting
add_alloc(
&mut main_byte_code,
4,
core_string_impl_size as u32,
"std::core::StringImpl",
);
add_mov_const(&mut main_byte_code, 1, "greeting", 0);
// Call StringImpl(greeting_bytes)
add_invoke_fn(
&mut main_byte_code,
"std::core::StringImpl::_ctor_0",
2,
&[0, 1],
5,
&[4, 2],
);
add_platform_call(&mut main_byte_code, "std::core::println", 3, 1, &vec![0u8]);
let main_dm_fn = DmFn::new("main", "main", main_byte_code, 2, None);
// Call println(greeting)
add_platform_call(&mut main_byte_code, "std::core::println", 6, &[4]);
let main_dm_fn = DmFn::new("main", "main", main_byte_code, 7, None);
greeting_lib.functions.push(Rc::new(main_dm_fn));
let mut state = DvmState::new();
let mut context = DvmContext::new();
context.load(vec![
Rc::new(greeting_lib),
Rc::new(string_lib),
Rc::new(array_lib),
Rc::new(mem_lib)
context.load_libs(vec![
Rc::new(greeting_lib),
Rc::new(string_lib),
Rc::new(array_lib),
]);
context.load_platform_fns(&init_platform_functions());
let main_fn = context.fn_by_fqn("main").unwrap();
call_fn(&mut state, &context, &main_fn, vec![]);

View File

@ -1,49 +1,49 @@
// use crate::util::trie::GetEdgeResult::{EdgeKeyIsPrefix, EqualKeys, KeyIsPrefix};
// use std::collections::HashMap;
// use std::rc::Rc;
//
//
// pub struct RadixTrie<T> {
// root: RadixTrieNode<T>,
// }
//
//
// struct RadixTrieNode<T> {
// edges: HashMap<String, RadixTrieNode<T>>,
// value: Option<Rc<T>>,
// }
//
//
// impl<T> RadixTrie<T> {
// pub fn new() -> Self {
// RadixTrie {
// root: Default::default(),
// }
// }
//
//
// pub fn insert(&mut self, key: &str, value: &Rc<T>) {
// self.root.insert_helper(key, value);
// }
//
//
// pub fn remove(&mut self, key: &str) {
// todo!()
// }
//
//
// pub fn find(&self, key: &str) -> Option<Rc<T>> {
// todo!()
// }
// }
//
//
// impl<T> Default for RadixTrieNode<T> {
// fn default() -> Self {
// RadixTrieNode::new()
// }
// }
//
//
// enum GetEdgeResult<'a, T> {
// EqualKeys,
// KeyIsPrefix(&'a str, &'a mut RadixTrieNode<T>), // common prefix and target node
// EdgeKeyIsPrefix(&'a str, &'a mut RadixTrieNode<T>), // non-common suffix and target node,
// None,
// }
//
//
// impl<T> RadixTrieNode<T> {
// fn new() -> Self {
// RadixTrieNode {
@ -51,14 +51,14 @@
// value: None,
// }
// }
//
//
// fn get_edge<'a>(&'a mut self, key: &'a str) -> GetEdgeResult<'a, T> {
// for (edge_key, edge_node) in self.edges.iter_mut() {
// // Case: edge_key == key: overwrite data
// if *key == *edge_key {
// return EqualKeys;
// }
//
//
// // Find how many common characters there are starting from the beginning and terminating
// // as soon as there is no match
// let mut i = 0;
@ -71,28 +71,28 @@
// break 'number_of_common_chars;
// }
// }
//
//
// // Case: key's first char does not match at all: continue searching
// if i == 0 {
// continue;
// }
//
//
// // Case: key is prefix of edge_key
// if i < edge_key.len() {
// return KeyIsPrefix(key, edge_node);
// }
//
//
// if i == edge_key.len() {
// panic!(
// "Should not have gotten here: counted common chars equals edge_key's length."
// )
// }
//
//
// return EdgeKeyIsPrefix(&edge_key[i..], edge_node);
// }
// GetEdgeResult::None
// }
//
//
// fn insert_helper(&mut self, key: &str, value: &Rc<T>) {
// match self.get_edge(key) {
// EqualKeys => {
@ -102,8 +102,8 @@
// KeyIsPrefix(prefix, edge_node) => {
// // split like asparagus break
// let old_target_node = self.edges.remove(key).unwrap();
//
//
//
//
// let mut common_prefix_node: RadixTrieNode<T> = RadixTrieNode::new();
// }
// EdgeKeyIsPrefix(suffix, edge_node) => {

View File

@ -5,7 +5,8 @@ pub enum DmType {
Long,
Double,
Boolean,
Pointer,
Object,
USize,
Unit,
}
@ -17,7 +18,8 @@ impl DmType {
DmType::Long => size_of::<i64>(),
DmType::Double => size_of::<f64>(),
DmType::Boolean => size_of::<bool>(),
DmType::Pointer => size_of::<usize>(),
DmType::Object => size_of::<usize>(),
DmType::USize => size_of::<usize>(),
DmType::Unit => todo!("Need to determine size of Unit... is it dependent on the size of the thing which is Unit?")
}
}

View File

@ -1,4 +1,4 @@
use crate::vm::mem::DmAllocObject;
use crate::vm::object::DmAllocObject;
use std::rc::Rc;
#[derive(Debug, Clone, PartialEq)]
@ -8,7 +8,8 @@ pub enum DvmValue {
Long(i64),
Double(f64),
Boolean(bool),
Pointer(Rc<DmAllocObject>),
Object(Rc<DmAllocObject>),
USize(usize),
Uninit,
Void,
}
@ -18,15 +19,23 @@ impl DvmValue {
if let DvmValue::Long(l) = self {
*l
} else {
panic!("Expected DvmValue::Long, but found {:?}", self)
panic!("Expected DvmValue::Long, but found DvmValue::{:?}", self)
}
}
pub fn expect_pointer(&self) -> Rc<DmAllocObject> {
if let DvmValue::Pointer(p) = self {
p.clone()
pub fn expect_object(&self) -> Rc<DmAllocObject> {
if let DvmValue::Object(o) = self {
o.clone()
} else {
panic!("Expected DvmValue::Pointer, but found {:?}", self);
panic!("Expected DvmValue::Object, but found DvmValue::{:?}", self);
}
}
pub fn expect_usize(&self) -> usize {
if let DvmValue::USize(u) = self {
*u
} else {
panic!("Expected DvmValue::USize, but found DvmValue::{:?}", self);
}
}
}

View File

@ -1,7 +1,7 @@
use crate::get_32_le;
use crate::vm::lib::DmLib;
use crate::vm::lib::magic::{CONST_SYMBOL, DEIMOS_MAGIC_NUMBER, FUNCTION_SYMBOL};
use crate::vm::lib::symbol::LibSymbol;
use crate::vm::lib::DmLib;
pub fn load_module(bytes: &[u8]) -> Result<DmLib, String> {
let mut ip: usize = 0;

View File

@ -1,5 +1,5 @@
use crate::vm::lib::DmLib;
use crate::vm::lib::magic::{COMPILER_VERSION_STRING, DEIMOS_MAGIC_STRING};
use crate::vm::lib::DmLib;
macro_rules! push_byte_array {
( $dest: expr, $arr: expr ) => {
@ -37,4 +37,4 @@ pub fn write_module(module: DmLib) -> Vec<u8> {
push_string!(result, COMPILER_VERSION_STRING);
result
}
}

View File

@ -1,40 +1,9 @@
use crate::vm::dm_type::DmType;
use crate::vm::dvm_value::DvmValue;
use crate::vm::object_type::{DmField, DmImplementation};
use std::alloc::{alloc, dealloc, Layout};
use std::collections::HashSet;
use crate::vm::object::DmAllocObject;
use crate::vm::object_type::DmField;
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);
@ -53,11 +22,14 @@ pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -
raw_data[0..data_size].try_into().unwrap(),
)),
DmType::Boolean => DvmValue::Boolean(raw_data[0] != 0),
DmType::Pointer => {
DmType::Object => {
// 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))
DvmValue::Object(Rc::from_raw(address as *const DmAllocObject))
}
DmType::USize => DvmValue::USize(usize::from_ne_bytes(
raw_data[0..data_size].try_into().unwrap(),
)),
DmType::Unit => DvmValue::Uninit,
}
}

View File

@ -2,14 +2,16 @@ pub mod dm_type;
pub mod dvm_value;
pub mod lib;
pub mod mem;
mod object;
pub mod object_type;
pub mod op_codes;
pub mod platform;
mod pointer;
pub mod util;
use crate::vm::dvm_value::DvmValue;
use crate::vm::lib::{DmConstant, DmLib};
use crate::vm::mem::{get_field_value, DmAllocObject};
use crate::vm::object::DmAllocObject;
use crate::vm::object_type::DmFn;
use op_codes::*;
use std::alloc::{alloc, dealloc, Layout};
@ -19,13 +21,15 @@ use std::rc::Rc;
pub type PlatformFunction =
fn(args: Vec<DvmValue>, state: &mut DvmState, context: &DvmContext) -> DvmValue;
#[derive(Debug)]
enum CallFrame {
PlatformCall(CallFrameInfo),
DeimosCall(CallFrameInfo),
}
#[derive(Debug)]
struct CallFrameInfo {
fn_fqn: String,
pub fqn: String,
}
pub struct DvmContext {
@ -43,7 +47,7 @@ impl DvmContext {
}
}
pub fn load(&mut self, libs: Vec<Rc<DmLib>>) {
pub fn load_libs(&mut self, libs: Vec<Rc<DmLib>>) {
for lib in libs {
self.libs.push(lib.clone());
for lib_fn in &lib.functions {
@ -75,14 +79,19 @@ impl DvmContext {
.iter()
.flat_map(|implementation| &implementation.methods)
{
self.functions.insert(
method.dm_fn().fqn().to_string(),
method.dm_fn().clone(),
);
self.functions
.insert(method.dm_fn().fqn().to_string(), method.dm_fn().clone());
}
}
}
pub fn load_platform_fns(&mut self, platform_fns: &HashMap<String, PlatformFunction>) {
for (fqn, platform_fn) in platform_fns {
self.platform_functions
.insert(fqn.to_string(), Rc::new(*platform_fn));
}
}
pub fn fn_by_fqn(&self, fqn: &str) -> Option<Rc<DmFn>> {
self.functions.get(fqn).cloned()
}
@ -108,6 +117,30 @@ impl DvmState {
}
}
macro_rules! dump_state {
( $message: expr, $state: expr ) => {
println!("----");
println!("{}", $message);
println!("----");
println!("Call stack:");
for call_frame in &$state.call_stack {
match call_frame {
CallFrame::PlatformCall(frame_info) => {
println!(" {}", frame_info.fqn);
}
CallFrame::DeimosCall(frame_info) => {
println!(" {}", frame_info.fqn);
}
}
}
println!("Registers: ");
for (i, register) in $state.registers.iter().enumerate() {
println!(" r{}: {:?}", i, register);
}
};
}
pub fn call_fn(
state: &mut DvmState,
context: &DvmContext,
@ -116,7 +149,7 @@ pub fn call_fn(
) -> DvmValue {
// save current state
state.call_stack.push(CallFrame::DeimosCall(CallFrameInfo {
fn_fqn: dm_fn.fqn().to_string(),
fqn: dm_fn.fqn().to_string(),
}));
state.register_state_stack.push(state.registers.clone());
@ -129,8 +162,8 @@ pub fn call_fn(
}
// push args
for arg in args {
state.registers.push(arg);
for (i, arg) in args.iter().enumerate() {
state.registers[i] = arg.clone();
}
// run the byte code
@ -233,31 +266,23 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
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));
state.registers[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));
state.registers[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));
state.registers[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())
state.registers[target_register] = source_value.clone();
}
ALLOC => {
let target_register = next_8!(iter, usize);
@ -275,13 +300,17 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
.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);
state.registers[target_register] = DvmValue::Object(Rc::new(dm_alloc_object));
}
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
.get(target_register)
.unwrap()
.expect_object();
drop(dm_alloc_object); // explicit
state.registers[target_register] = DvmValue::Uninit;
}
MOV_INT_TO => {
let target_register = next_8!(iter, usize);
@ -292,7 +321,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
.registers
.get(target_register)
.unwrap()
.expect_pointer();
.expect_object();
write_bytes!(dm_alloc_object.data, offset, operand.to_ne_bytes());
}
MOV_LONG_TO => {
@ -312,7 +341,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
.registers
.get(target_register)
.unwrap()
.expect_pointer();
.expect_object();
let source_value = state.registers.get(source_register).unwrap();
match source_value {
@ -331,14 +360,17 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
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());
DvmValue::Object(source_object) => {
let source_object_ptr = Rc::into_raw(source_object.clone());
write_bytes!(
target_alloc_object.data,
offset,
(source_ptr as usize).to_ne_bytes()
(source_object_ptr as usize).to_ne_bytes()
);
}
DvmValue::USize(us) => {
write_bytes!(target_alloc_object.data, offset, us.to_ne_bytes());
}
DvmValue::Uninit => {
panic!("Cannot move DvmValue::Uninit to object.")
}
@ -348,15 +380,11 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
}
}
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 address_register = next_8!(iter, usize);
let size_register = next_8!(iter, usize);
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);
let const_id = next_32_le!(iter, usize);
// Get constant
let Some(lib) = context.libs.iter().find(|lib| lib.name == lib_name) else {
@ -365,118 +393,49 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
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();
// Alloc memory for constant
let size = s.len();
let layout = Layout::from_size_align(size, 1).unwrap();
let raw_pointer = unsafe { alloc(layout) };
// 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,
)
// Move constant to memory
let bytes = s.as_bytes();
for i in 0..size {
unsafe {
raw_pointer.add(i).write(bytes[i]);
}
}
.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()),
],
);
// Store the pointer metadata in target registers.
state.registers[address_register] = DvmValue::USize(raw_pointer as usize);
state.registers[size_register] = DvmValue::USize(size);
}
ALLOC_RAW => {
// Allocates a raw number of bytes, with the number of bytes determined by the value
// of the source register. The address is stored in the target register as a
// DvmValue::Long.
let target_register = next_8!(iter, usize);
// of the source register.
let address_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))
let size = state.registers.get(source_register).unwrap().expect_long() as usize;
let layout = Layout::from_size_align(size, 1).unwrap();
let raw_ptr = unsafe { alloc(layout) };
state.registers[address_register] = DvmValue::USize(raw_ptr as usize);
}
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;
// Deallocates a DvmValue::Pointer(DvmPointer) in the target register.
let address_register = next_8!(iter, usize);
let size_register = next_8!(iter, usize);
let address = state
.registers
.get(address_register)
.unwrap()
.expect_usize();
let size = state.registers.get(size_register).unwrap().expect_usize();
let layout = Layout::from_size_align(size, 1).unwrap();
unsafe {
dealloc(ptr, layout);
dealloc(address as *mut u8, layout);
}
state.registers.insert(target_register, DvmValue::Uninit);
state.registers[address_register] = DvmValue::Uninit;
state.registers[size_register] = DvmValue::Uninit;
}
PLATFORM_CALL => {
// Calls a platform function. The result of the platform call is stored in the
@ -498,11 +457,9 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
.clone();
state
.call_stack
.push(CallFrame::PlatformCall(CallFrameInfo {
fn_fqn: symbol_name,
}));
.push(CallFrame::PlatformCall(CallFrameInfo { fqn: symbol_name }));
let call_result = platform_function(args, state, context);
state.registers.insert(return_register, call_result);
state.registers[return_register] = call_result;
state.call_stack.pop();
}
INVOKE_FN => {
@ -518,7 +475,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
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);
state.registers[return_register] = call_result;
}
INVOKE_VIRTUAL => {
let symbol_name = read_string!(iter);
@ -531,7 +488,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
args.push(value.clone());
}
let self_obj = args.get(0).unwrap().expect_pointer();
let self_obj = args.get(0).unwrap().expect_object();
let method = self_obj
.implementation
.get_method(&symbol_name, &self_obj)
@ -539,7 +496,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
let dm_fn = method.dm_fn();
let call_result = call_fn(state, context, &dm_fn, args);
state.registers.insert(return_register, call_result);
state.registers[return_register] = call_result;
}
INVOKE_DYNAMIC => {
unimplemented!("INVOKE_DYNAMIC is not yet supported and may never be.")

34
src/vm/object.rs Normal file
View File

@ -0,0 +1,34 @@
use crate::vm::object_type::DmImplementation;
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);
}
}
}

View File

@ -1,5 +1,5 @@
use crate::vm::dm_type::DmType;
use crate::vm::mem::DmAllocObject;
use crate::vm::object::DmAllocObject;
use std::fmt::Debug;
use std::rc::Rc;

View File

@ -75,9 +75,9 @@ pub fn add_mov_register(code: &mut Vec<u8>, target_register: u8, source_register
code.push(source_register);
}
pub fn add_alloc(code: &mut Vec<u8>, register: u8, size: u32, implementation_name: &str) {
pub fn add_alloc(code: &mut Vec<u8>, target_register: u8, size: u32, implementation_name: &str) {
code.push(ALLOC);
code.push(register);
code.push(target_register);
push_number!(code, size);
push_number!(code, implementation_name.len() as u32);
push_string!(code, implementation_name);
@ -113,9 +113,16 @@ pub fn add_mov_register_to(
code.push(source_register);
}
pub fn add_mov_const(code: &mut Vec<u8>, register: u8, lib_name: &str, const_id: u32) {
pub fn add_mov_const(
code: &mut Vec<u8>,
address_register: u8,
size_register: u8,
lib_name: &str,
const_id: u32,
) {
code.push(MOV_CONST);
code.push(register);
code.push(address_register);
code.push(size_register);
push_number!(code, lib_name.len() as u32);
push_string!(code, lib_name);
push_number!(code, const_id);
@ -125,14 +132,13 @@ pub fn add_platform_call(
code: &mut Vec<u8>,
symbol_name: &str,
return_register: u8,
arg_registers_length: u8,
arg_registers: &Vec<u8>,
arg_registers: &[u8],
) {
code.push(PLATFORM_CALL);
push_number!(code, symbol_name.len() as u32);
push_string!(code, symbol_name);
push_number!(code, return_register);
push_number!(code, arg_registers_length);
push_number!(code, arg_registers.len() as u8);
for &b in arg_registers {
code.push(b);
}

View File

@ -1,5 +1,6 @@
use crate::vm::dvm_value::DvmValue;
use crate::vm::mem::{get_field_value, DmAllocObject};
use crate::vm::mem::get_field_value;
use crate::vm::object::DmAllocObject;
use crate::vm::{DvmContext, DvmState};
use std::rc::Rc;
@ -30,14 +31,15 @@ unsafe fn get_string(dvm_value: &DvmValue) -> String {
DvmValue::Long(l) => l.to_string(),
DvmValue::Double(d) => d.to_string(),
DvmValue::Boolean(b) => b.to_string(),
DvmValue::Pointer(object) => convert_to_string(object.clone()),
DvmValue::Object(object) => object_to_string(object.clone()),
DvmValue::USize(u) => u.to_string(),
DvmValue::Uninit => String::from("Uninit"),
DvmValue::Void => String::from("Void"),
}
}
fn convert_to_string(alloc_object_rc: Rc<DmAllocObject>) -> String {
if alloc_object_rc.implementation.fqn == "std::core::String" {
fn object_to_string(alloc_object_rc: Rc<DmAllocObject>) -> String {
if alloc_object_rc.implementation.fqn == "std::core::StringImpl" {
extract_string_from_string(alloc_object_rc.clone())
} else {
todo!("what happens if we don't have a String?")
@ -49,36 +51,27 @@ fn extract_string_from_string(string_object: Rc<DmAllocObject>) -> String {
.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();
let bytes_object = unsafe { get_field_value(&bytes_field, &string_object) }.expect_object();
if bytes_object.implementation.fqn != "std::core::ArrayImpl" {
panic!("String.bytes field is not a std::core::ArrayImpl");
}
let pointer_field = bytes_object
let ptr_address_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");
}
.get_field("ptr_address", &bytes_object)
.expect("Could not get ArrayImpl.ptr_address field.");
let address = unsafe { get_field_value(&ptr_address_field, &bytes_object) }.expect_usize();
let raw_address_field = pointer_object
let ptr_size_field = bytes_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();
.get_field("ptr_size", &bytes_object)
.expect("Could not get ArrayImpl.ptr_size field.");
let size = unsafe { get_field_value(&ptr_size_field, &bytes_object) }.expect_usize();
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 raw_bytes_pointer = address 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() });
for i in 0..size {
v.push(unsafe { raw_bytes_pointer.add(i).read() });
}
String::from_utf8(v).unwrap()
}

27
src/vm/pointer.rs Normal file
View File

@ -0,0 +1,27 @@
use std::fmt::{Display, Formatter};
#[derive(Debug, PartialEq, Eq)]
pub struct DvmPointer {
address: *mut u8,
size: usize,
}
impl DvmPointer {
pub fn new(address: *mut u8, size: usize) -> DvmPointer {
DvmPointer { address, size }
}
pub fn address(&self) -> *mut u8 {
self.address
}
pub fn size(&self) -> usize {
self.size
}
}
impl Display for DvmPointer {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("0x{:x}", self.address as usize))
}
}