Compare commits

...

2 Commits

Author SHA1 Message Date
Jesse Brault
71ee49761e Updated dvm/main.rs to use new refactored dvm. 2025-04-13 10:20:29 -05:00
Jesse Brault
26d87acff5 More refactoring of dvm; add DvmValue::String and related. 2025-04-13 09:34:09 -05:00
11 changed files with 407 additions and 337 deletions

View File

@ -1,163 +1,69 @@
use deimos::vm::field::DvmField; use deimos::vm::constant::DvmConstant;
use deimos::vm::function::DvmFunction; use deimos::vm::function::DvmFunction;
use deimos::vm::implementation::DvmImplementation; use deimos::vm::instruction::{Immediate, Instruction, Location};
use deimos::vm::interface::DmInterface; use deimos::vm::platform::get_std_lib_platform_functions;
use deimos::vm::lib::{DmConstant, DmLib}; use deimos::vm::source_code_location::SourceCodeLocation;
use deimos::vm::method::DvmMethod; use deimos::vm::{dump_state, run_main_function, DvmContext, DvmState};
use deimos::vm::op_codes::{
add_alloc, add_dealloc, add_invoke_fn, add_mov_const, add_platform_call, add_store,
};
use deimos::vm::platform::init_platform_functions;
use deimos::vm::r#type::DvmType;
use deimos::vm::{call_fn, DvmContext, DvmState};
use std::rc::Rc; use std::rc::Rc;
fn main() { fn main() {
// Goal: // Goal:
// - write a single lib with a main() // - write a single lib with a main()
// - call the main fn // - call the main fn
// fn main() { println "Hello, World!" } //
// ns greeter
//
// fn main() {
// println "Hello, World!"
// }
let main_instructions = vec![
Instruction::MoveImmediate {
destination: Location::Register(0),
immediate: Immediate::Constant(DvmConstant::String(String::from("Hello, World!"))),
},
Instruction::Push { source_register: 0 },
Instruction::InvokeStaticPlatform {
function_name: Rc::new(String::from("std::core::println")),
source_code_location: SourceCodeLocation {
source_file_name: String::from("greeter.dm"),
line: 4,
char: 5,
},
},
Instruction::Pop {
// println return value
destination_register: None,
},
Instruction::Pop {
// arg0 to println
destination_register: None,
},
Instruction::MoveImmediate {
destination: Location::Register(1),
immediate: Immediate::Int(0),
},
Instruction::Push { source_register: 1 },
Instruction::Return,
];
// std/core/array lib let main_function = DvmFunction::new(
let mut array_lib = DmLib::new("std/core/array"); "greeter::main",
&main_instructions,
// std::core::Array SourceCodeLocation {
let array_int = DmInterface::new("std::core::Array"); source_file_name: String::from("greeter.dm"),
array_lib.add_interface(array_int); line: 3,
let array_int_rc = array_lib char: 1,
.interfaces() },
.iter()
.find(|interface| interface.fqn() == "std::core::Array")
.unwrap();
// std::core::ArrayImpl
let mut array_impl = DvmImplementation::new("std::core::ArrayImpl", Some(array_int_rc.clone()));
let array_impl_ptr_address_fld = DvmField::new("ptr_address", DvmType::USize);
let array_impl_ptr_size_fld = DvmField::new("ptr_size", DvmType::USize);
let array_impl_length_fld = DvmField::new("length", DvmType::Long);
array_impl.add_field(array_impl_ptr_address_fld);
array_impl.add_field(array_impl_ptr_size_fld);
array_impl.add_field(array_impl_length_fld);
// std::core::ArrayImpl::_ctor_0(
// r0: self
// r1: USize ptr_address
// r2: USize ptr_size
// r3: Long length
// )
let mut array_impl_ctor_0_bytecode: Vec<u8> = Vec::new();
add_store(&mut array_impl_ctor_0_bytecode, 0, 0, 1);
add_store(&mut array_impl_ctor_0_bytecode, 0, 1, 2);
add_store(&mut array_impl_ctor_0_bytecode, 0, 2, 3);
let array_impl_ctor_0_fn = DvmFunction::new(
"std::core::ArrayImpl::_ctor_0",
"_ctor_0",
array_impl_ctor_0_bytecode,
4,
None,
); );
let array_impl_ctor_0_method = DvmMethod::new(array_impl_ctor_0_fn, None);
array_impl.add_method(array_impl_ctor_0_method);
array_lib.add_implementation(array_impl);
// std::core::String
let mut string_lib = DmLib::new("std/core/string");
let string_int = DmInterface::new("std::core::String");
string_lib.add_interface(string_int);
let string_int_rc = string_lib
.interfaces()
.iter()
.find(|interface| interface.fqn() == "std::core::String")
.unwrap();
let mut string_impl =
DvmImplementation::new("std::core::StringImpl", Some(string_int_rc.clone()));
let bytes_field = DvmField::new("bytes", DvmType::Object);
string_impl.add_field(bytes_field);
// std::core::String::_ctor_0(
// r0: self
// r1: Array<Byte> bytes
// )
let mut string_ctor_0_bytecode: Vec<u8> = Vec::new();
add_store(&mut string_ctor_0_bytecode, 0, 0, 1);
let string_ctor_0_fn = DvmFunction::new(
"std::core::StringImpl::_ctor_0",
"_ctor_0",
string_ctor_0_bytecode,
2,
None,
);
let string_ctor_0_method = DvmMethod::new(string_ctor_0_fn, None);
string_impl.add_method(string_ctor_0_method);
string_lib.add_implementation(string_impl);
// greeting lib
let mut greeting_lib = DmLib::new("greeting");
greeting_lib.add_constant(DmConstant::String("Hello, World!".to_string()));
let mut main_byte_code = Vec::new();
// 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, 2, "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, "std::core::StringImpl");
// Call StringImpl(greeting_bytes)
add_invoke_fn(
&mut main_byte_code,
"std::core::StringImpl::_ctor_0",
5,
&[4, 2],
);
// Call println(greeting)
add_platform_call(&mut main_byte_code, "std::core::println", 6, &[4]);
// Dealloc StringImpl
add_dealloc(&mut main_byte_code, 4);
// Dealloc ArrayImpl
add_dealloc(&mut main_byte_code, 2);
let main_dm_fn = DvmFunction::new("main", "main", main_byte_code, 7, None);
greeting_lib.add_function(main_dm_fn);
let mut state = DvmState::new(); let mut state = DvmState::new();
let mut context = DvmContext::new(); let mut context = DvmContext::new(Rc::new(main_function));
context.load_libs(vec![ context.add_platform_functions(get_std_lib_platform_functions());
Rc::new(greeting_lib), let exit_code = run_main_function(&mut state, &context);
Rc::new(string_lib),
Rc::new(array_lib),
]);
context.load_platform_fns(init_platform_functions());
let main_fn = context.fn_by_fqn("main").unwrap(); dump_state(&state, "After main!");
call_fn(&mut state, &context, &main_fn, vec![]);
if exit_code != 0 {
std::process::exit(exit_code);
}
} }

View File

@ -1,5 +1,4 @@
use crate::vm::object::DvmObject; use crate::vm::object::DvmObject;
use crate::vm::pointer::DvmPointer;
use crate::vm::value::DvmValue; use crate::vm::value::DvmValue;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt::{Display, Write}; use std::fmt::{Display, Write};
@ -16,7 +15,7 @@ pub enum DvmArray {
Booleans(Vec<bool>), Booleans(Vec<bool>),
Objects(Vec<Rc<RefCell<DvmObject>>>), Objects(Vec<Rc<RefCell<DvmObject>>>),
Arrays(Vec<Rc<RefCell<DvmArray>>>), Arrays(Vec<Rc<RefCell<DvmArray>>>),
ConstantPointers(Vec<DvmPointer>), Strings(Vec<Rc<String>>),
} }
impl DvmArray { impl DvmArray {
@ -30,7 +29,7 @@ impl DvmArray {
DvmArray::Booleans(vec) => DvmValue::Boolean(vec[index]), DvmArray::Booleans(vec) => DvmValue::Boolean(vec[index]),
DvmArray::Objects(vec) => DvmValue::Object(vec[index].clone()), DvmArray::Objects(vec) => DvmValue::Object(vec[index].clone()),
DvmArray::Arrays(vec) => DvmValue::Array(vec[index].clone()), DvmArray::Arrays(vec) => DvmValue::Array(vec[index].clone()),
DvmArray::ConstantPointers(vec) => DvmValue::ConstantPointer(vec[index].clone()), DvmArray::Strings(vec) => DvmValue::String(vec[index].clone()),
} }
} }
@ -60,8 +59,8 @@ impl DvmArray {
DvmArray::Arrays(vec) => { DvmArray::Arrays(vec) => {
vec[index] = value.expect_array(); vec[index] = value.expect_array();
} }
DvmArray::ConstantPointers(vec) => { DvmArray::Strings(vec) => {
vec[index] = value.expect_constant_pointer(); vec[index] = value.expect_string();
} }
} }
} }
@ -89,7 +88,7 @@ pub enum DvmArrayIter<'a> {
Booleans(Iter<'a, bool>), Booleans(Iter<'a, bool>),
Objects(Iter<'a, Rc<RefCell<DvmObject>>>), Objects(Iter<'a, Rc<RefCell<DvmObject>>>),
Arrays(Iter<'a, Rc<RefCell<DvmArray>>>), Arrays(Iter<'a, Rc<RefCell<DvmArray>>>),
ConstantPointers(Iter<'a, DvmPointer>), Strings(Iter<'a, Rc<String>>),
} }
impl<'a> Iterator for DvmArrayIter<'a> { impl<'a> Iterator for DvmArrayIter<'a> {
@ -104,9 +103,7 @@ impl<'a> Iterator for DvmArrayIter<'a> {
DvmArrayIter::Booleans(iter) => iter.next().map(|b| DvmValue::Boolean(*b)), DvmArrayIter::Booleans(iter) => iter.next().map(|b| DvmValue::Boolean(*b)),
DvmArrayIter::Objects(iter) => iter.next().map(|o| DvmValue::Object(o.clone())), DvmArrayIter::Objects(iter) => iter.next().map(|o| DvmValue::Object(o.clone())),
DvmArrayIter::Arrays(iter) => iter.next().map(|a| DvmValue::Array(a.clone())), DvmArrayIter::Arrays(iter) => iter.next().map(|a| DvmValue::Array(a.clone())),
DvmArrayIter::ConstantPointers(iter) => { DvmArrayIter::Strings(iter) => iter.next().map(|s| DvmValue::String(s.clone())),
iter.next().map(|p| DvmValue::ConstantPointer(p.clone()))
}
} }
} }
} }
@ -125,7 +122,7 @@ impl<'a> IntoIterator for &'a DvmArray {
DvmArray::Booleans(v) => DvmArrayIter::Booleans(v.iter()), DvmArray::Booleans(v) => DvmArrayIter::Booleans(v.iter()),
DvmArray::Objects(v) => DvmArrayIter::Objects(v.iter()), DvmArray::Objects(v) => DvmArrayIter::Objects(v.iter()),
DvmArray::Arrays(v) => DvmArrayIter::Arrays(v.iter()), DvmArray::Arrays(v) => DvmArrayIter::Arrays(v.iter()),
DvmArray::ConstantPointers(v) => DvmArrayIter::ConstantPointers(v.iter()), DvmArray::Strings(v) => DvmArrayIter::Strings(v.iter()),
} }
} }
} }

17
src/vm/constant.rs Normal file
View File

@ -0,0 +1,17 @@
#[derive(Debug, Clone)]
pub enum DvmConstant {
String(String),
Array(DvmConstantArray)
}
#[derive(Debug, Clone)]
pub enum DvmConstantArray {
Bytes(Vec<u8>),
Ints(Vec<i32>),
Longs(Vec<i64>),
Doubles(Vec<f64>),
USizes(Vec<usize>),
Booleans(Vec<bool>),
Strings(Vec<String>),
Arrays(Vec<DvmConstantArray>)
}

View File

@ -1,16 +1,23 @@
use crate::vm::instruction::Instruction; use crate::vm::instruction::Instruction;
use crate::vm::source_code_location::SourceCodeLocation;
#[derive(Debug)] #[derive(Debug)]
pub struct DvmFunction { pub struct DvmFunction {
fqn: String, fqn: String,
instructions: Vec<Instruction>, instructions: Vec<Instruction>,
source_code_location: SourceCodeLocation,
} }
impl DvmFunction { impl DvmFunction {
pub fn new(fqn: &str, instructions: &[Instruction]) -> Self { pub fn new(
fqn: &str,
instructions: &[Instruction],
source_code_location: SourceCodeLocation,
) -> Self {
DvmFunction { DvmFunction {
fqn: fqn.to_string(), fqn: fqn.to_string(),
instructions: Vec::from(instructions), instructions: Vec::from(instructions),
source_code_location,
} }
} }
@ -21,6 +28,10 @@ impl DvmFunction {
pub fn instructions(&self) -> &Vec<Instruction> { pub fn instructions(&self) -> &Vec<Instruction> {
&self.instructions &self.instructions
} }
pub fn source_code_location(&self) -> &SourceCodeLocation {
&self.source_code_location
}
} }
impl PartialEq for DvmFunction { impl PartialEq for DvmFunction {

View File

@ -1,3 +1,5 @@
use crate::vm::constant::DvmConstant;
use crate::vm::source_code_location::SourceCodeLocation;
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -14,7 +16,7 @@ pub enum Instruction {
source_register: usize, source_register: usize,
}, },
Pop { Pop {
destination_register: usize, destination_register: Option<usize>,
}, },
AllocateObject { AllocateObject {
implementation_name: Rc<String>, implementation_name: Rc<String>,
@ -29,8 +31,13 @@ pub enum Instruction {
function_name: Rc<String>, function_name: Rc<String>,
source_code_location: SourceCodeLocation, source_code_location: SourceCodeLocation,
}, },
PlatformCall { InvokeStaticPlatform {
platform_function_name: Rc<String>, function_name: Rc<String>,
source_code_location: SourceCodeLocation,
},
InvokeObjectPlatform {
object_register: usize,
function_name: Rc<String>,
source_code_location: SourceCodeLocation, source_code_location: SourceCodeLocation,
}, },
Add { Add {
@ -107,10 +114,7 @@ pub enum Immediate {
Double(f64), Double(f64),
Usize(usize), Usize(usize),
Boolean(bool), Boolean(bool),
ConstantPointer { Constant(DvmConstant),
raw_pointer: *const u8,
length: usize
},
Empty, Empty,
} }
@ -130,10 +134,3 @@ pub enum Location {
offset: Option<isize>, offset: Option<isize>,
}, },
} }
#[derive(Debug, Clone)]
pub struct SourceCodeLocation {
pub source_file_name: String,
pub line: i64,
pub char: i64,
}

View File

@ -1,47 +1,52 @@
mod array; mod array;
pub mod constant;
mod field; mod field;
mod function; pub mod function;
pub mod implementation; pub mod implementation;
mod instruction; pub mod instruction;
mod interface; mod interface;
pub mod lib; pub mod lib;
mod method; mod method;
pub mod object; pub mod object;
pub mod op_codes; pub mod op_codes;
pub mod platform; pub mod platform;
mod pointer; pub mod source_code_location;
pub mod r#type; pub mod r#type;
pub mod util; pub mod util;
pub mod value; pub mod value;
mod virtual_method; mod virtual_method;
use crate::vm::array::DvmArray;
use crate::vm::constant::{DvmConstant, DvmConstantArray};
use crate::vm::implementation::DvmImplementation; use crate::vm::implementation::DvmImplementation;
use crate::vm::instruction::{Immediate, Instruction, Location, SourceCodeLocation}; use crate::vm::instruction::{Immediate, Instruction, Location};
use crate::vm::object::DvmObject; use crate::vm::object::DvmObject;
use crate::vm::pointer::DvmPointer;
use crate::vm::value::DvmValue; use crate::vm::value::DvmValue;
use function::DvmFunction; use function::DvmFunction;
use source_code_location::SourceCodeLocation;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Display; use std::fmt::Display;
use std::rc::Rc; use std::rc::Rc;
fn dvm_panic(context: &DvmContext, message: &str) { pub fn dump_state(state: &DvmState, message: &str) {
println!("----"); println!("----");
println!("Deimos Virtual Machine: Panic!");
println!("{}", message); println!("{}", message);
println!("----"); println!("----");
println!("Current Instruction: {:?}", context.current_instruction); println!(
"Current Instruction: {:?}",
state.current_instruction.clone().unwrap()
);
println!("Registers:"); println!("Registers:");
for (i, register) in context.registers.iter().enumerate() { for (i, register) in state.registers.iter().enumerate() {
println!("\tr{}: {:?}", i, register); println!("\tr{:x}: {:?}", i, register);
} }
println!("Call stack:"); println!("Call stack:");
for call in context.call_stack.iter() { for call in state.call_stack.iter() {
println!("\t{}", call); println!("\t{}", call);
} }
println!("Stack:"); println!("Stack:");
for (i, value) in context.stack.iter().enumerate() { for (i, value) in state.stack.iter().enumerate() {
println!("\t{}: {}", i, value); println!("\t{}: {}", i, value);
} }
println!("----"); println!("----");
@ -49,33 +54,27 @@ fn dvm_panic(context: &DvmContext, message: &str) {
macro_rules! dvm_panic { macro_rules! dvm_panic {
($context: expr, $message: expr) => { ($context: expr, $message: expr) => {
dvm_panic($context, $message); dump_state($context, $message);
panic!() panic!()
}; };
} }
pub type PlatformFunction = fn(context: &mut DvmContext); pub type PlatformFunction = fn(state: &mut DvmState, context: &DvmContext);
pub struct DvmContext { pub struct DvmState {
call_stack: Vec<DvmCall>, call_stack: Vec<DvmCall>,
current_instruction: Option<Instruction>, current_instruction: Option<Instruction>,
registers: Vec<DvmValue>, registers: Vec<DvmValue>,
stack: Vec<DvmValue>, stack: Vec<DvmValue>,
implementations: HashMap<String, Rc<DvmImplementation>>,
static_functions: HashMap<String, Rc<DvmFunction>>,
platform_functions: HashMap<String, PlatformFunction>,
} }
impl DvmContext { impl DvmState {
pub fn new() -> Self { pub fn new() -> Self {
DvmContext { DvmState {
call_stack: vec![], call_stack: vec![],
current_instruction: None, current_instruction: None,
registers: vec![], registers: vec![DvmValue::Empty; 16],
stack: vec![], stack: vec![],
implementations: HashMap::new(),
static_functions: HashMap::new(),
platform_functions: HashMap::new(),
} }
} }
@ -84,6 +83,42 @@ impl DvmContext {
dvm_panic!(self, "Stack underflow!"); dvm_panic!(self, "Stack underflow!");
}) })
} }
pub fn get_stack_argument(&self, index: usize) -> DvmValue {
self.stack
.get(self.stack.len() - 2 - index)
.unwrap_or_else(|| {
dvm_panic!(self, "Stack underflow!");
})
.clone()
}
}
pub struct DvmContext {
main_function: Rc<DvmFunction>,
implementations: HashMap<String, Rc<DvmImplementation>>,
static_functions: HashMap<String, Rc<DvmFunction>>,
platform_functions: HashMap<String, PlatformFunction>,
}
impl DvmContext {
pub fn new(main_function: Rc<DvmFunction>) -> Self {
DvmContext {
main_function,
implementations: HashMap::new(),
static_functions: HashMap::new(),
platform_functions: HashMap::new(),
}
}
pub fn add_platform_functions(
&mut self,
platform_functions: HashMap<String, PlatformFunction>,
) {
for (fqn, platform_function) in platform_functions {
self.platform_functions.insert(fqn, platform_function);
}
}
} }
pub struct DvmCall { pub struct DvmCall {
@ -114,16 +149,16 @@ fn update_index(index: &mut usize, offset: isize) {
fn push_call_frame( fn push_call_frame(
function_name: Rc<String>, function_name: Rc<String>,
source_code_location: SourceCodeLocation, source_code_location: SourceCodeLocation,
context: &mut DvmContext, state: &mut DvmState,
) { ) {
context.call_stack.push(DvmCall { state.call_stack.push(DvmCall {
function_name, function_name,
source_code_location, source_code_location,
}); });
} }
fn pop_call_frame(context: &mut DvmContext) { fn pop_call_frame(state: &mut DvmState) {
context.call_stack.pop(); state.call_stack.pop();
} }
fn compute_index_with_offset( fn compute_index_with_offset(
@ -146,17 +181,17 @@ fn compute_index_with_offset(
} }
} }
fn copy_from_source(context: &DvmContext, source: &Location) -> DvmValue { fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue {
match source { match source {
Location::Register(register) => context.registers[*register].clone(), Location::Register(register) => state.registers[*register].clone(),
Location::Stack { offset } => context.stack[*offset].clone(), Location::Stack { offset } => state.stack[*offset].clone(),
Location::Field { Location::Field {
object_register, object_register,
field_name, field_name,
} => context.registers[*object_register].map_object( } => state.registers[*object_register].map_object(
|o| o.borrow().read_field(field_name).clone(), |o| o.borrow().read_field(field_name).clone(),
|v| { |v| {
dvm_panic!(context, &format!("Expected an object, but found: {}", v)); dvm_panic!(state, &format!("Expected an object, but found: {}", v));
}, },
), ),
Location::Array { Location::Array {
@ -164,30 +199,30 @@ fn copy_from_source(context: &DvmContext, source: &Location) -> DvmValue {
index_register, index_register,
offset, offset,
} => { } => {
let index = compute_index_with_offset(&context.registers, *index_register, offset); let index = compute_index_with_offset(&state.registers, *index_register, offset);
context.registers[*array_register].map_array( state.registers[*array_register].map_array(
|a| a.borrow().read_element(index), |a| a.borrow().read_element(index),
|v| { |v| {
dvm_panic!(context, &format!("Expected an array, but found: {}", v)); dvm_panic!(state, &format!("Expected an array, but found: {}", v));
}, },
) )
} }
} }
} }
fn write_to_destination(context: &mut DvmContext, destination: &Location, value: DvmValue) { fn write_to_destination(state: &mut DvmState, destination: &Location, value: DvmValue) {
match destination { match destination {
Location::Register(register) => { Location::Register(register) => {
context.registers[*register] = value; state.registers[*register] = value;
} }
Location::Stack { offset } => { Location::Stack { offset } => {
context.stack[*offset] = value; state.stack[*offset] = value;
} }
Location::Field { Location::Field {
object_register, object_register,
field_name, field_name,
} => { } => {
context.registers[*object_register] state.registers[*object_register]
.expect_object() .expect_object()
.borrow_mut() .borrow_mut()
.write_field(field_name, value); .write_field(field_name, value);
@ -197,8 +232,8 @@ fn write_to_destination(context: &mut DvmContext, destination: &Location, value:
index_register, index_register,
offset, offset,
} => { } => {
let index = compute_index_with_offset(&context.registers, *index_register, offset); let index = compute_index_with_offset(&state.registers, *index_register, offset);
context.registers[*array_register] state.registers[*array_register]
.expect_array() .expect_array()
.borrow_mut() .borrow_mut()
.write_element(index, value); .write_element(index, value);
@ -206,6 +241,32 @@ fn write_to_destination(context: &mut DvmContext, destination: &Location, value:
} }
} }
fn constant_array_to_array(constant_array: &DvmConstantArray) -> DvmArray {
match constant_array {
DvmConstantArray::Bytes(v) => DvmArray::Bytes(v.clone()),
DvmConstantArray::Ints(v) => DvmArray::Ints(v.clone()),
DvmConstantArray::Longs(v) => DvmArray::Longs(v.clone()),
DvmConstantArray::Doubles(v) => DvmArray::Doubles(v.clone()),
DvmConstantArray::USizes(v) => DvmArray::USizes(v.clone()),
DvmConstantArray::Booleans(v) => DvmArray::Booleans(v.clone()),
DvmConstantArray::Strings(vs) => {
DvmArray::Strings(vs.iter().map(|s| Rc::new(s.clone())).collect())
}
DvmConstantArray::Arrays(va) => DvmArray::Arrays(
va.iter()
.map(|a| Rc::new(RefCell::new(constant_array_to_array(a))))
.collect(),
),
}
}
fn constant_to_value(constant: &DvmConstant) -> DvmValue {
match constant {
DvmConstant::String(s) => DvmValue::String(Rc::new(s.clone())),
DvmConstant::Array(a) => DvmValue::Array(Rc::new(RefCell::new(constant_array_to_array(a)))),
}
}
fn immediate_to_value(immediate: &Immediate) -> DvmValue { fn immediate_to_value(immediate: &Immediate) -> DvmValue {
match immediate { match immediate {
Immediate::Byte(b) => DvmValue::Byte(*b), Immediate::Byte(b) => DvmValue::Byte(*b),
@ -214,137 +275,220 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue {
Immediate::Double(d) => DvmValue::Double(*d), Immediate::Double(d) => DvmValue::Double(*d),
Immediate::Usize(s) => DvmValue::USize(*s), Immediate::Usize(s) => DvmValue::USize(*s),
Immediate::Boolean(b) => DvmValue::Boolean(*b), Immediate::Boolean(b) => DvmValue::Boolean(*b),
Immediate::ConstantPointer { Immediate::Constant(c) => constant_to_value(c),
raw_pointer,
length,
} => DvmValue::ConstantPointer(DvmPointer {
raw_pointer: *raw_pointer,
length: *length,
}),
Immediate::Empty => DvmValue::Empty, Immediate::Empty => DvmValue::Empty,
} }
} }
pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 {
let main_function = context.main_function.clone();
push_call_frame(
Rc::new(main_function.fqn().to_string()),
main_function.source_code_location().clone(),
state,
);
run(main_function.instructions(), state, context);
pop_call_frame(state);
state.pop_stack().expect_int_or_else(|v| {
dvm_panic!(state, &format!("Expected DvmValue::Int, but found {}", v));
})
}
// TODO: find all possible unwraps/expects and wrap with call to dvm_panic // TODO: find all possible unwraps/expects and wrap with call to dvm_panic
pub fn run(instructions: &[Instruction], context: &mut DvmContext) { pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmContext) {
let mut index = 0; let mut index = 0;
while index < instructions.len() { while index < instructions.len() {
context.current_instruction = Some(instructions[index].clone()); state.current_instruction = Some(instructions[index].clone());
index += 1; use Instruction::*;
match &instructions[index] { match &instructions[index] {
Instruction::MoveImmediate { MoveImmediate {
destination, destination,
immediate, immediate,
} => { } => {
write_to_destination(context, destination, immediate_to_value(immediate)); write_to_destination(state, destination, immediate_to_value(immediate));
} }
Instruction::Copy { Copy {
source, source,
destination, destination,
} => { } => {
let value = copy_from_source(context, source); let value = copy_from_source(state, source);
write_to_destination(context, destination, value); write_to_destination(state, destination, value);
} }
Instruction::Push { source_register } => { Push { source_register } => {
context state.stack.push(state.registers[*source_register].clone());
.stack
.push(context.registers[*source_register].clone());
} }
Instruction::Pop { Pop {
destination_register, destination_register,
} => { } => {
let value = context.stack.pop().expect("Stack underflow"); let value = state.stack.pop().unwrap_or_else(|| {
context.registers[*destination_register] = value; dvm_panic!(state, "Stack underflow");
});
if let Some(register_index) = destination_register {
state.registers[*register_index] = value;
}
} }
Instruction::AllocateObject { AllocateObject {
implementation_name, implementation_name,
destination_register, destination_register,
} => { } => {
let implementation = context let implementation = context
.implementations .implementations
.get(implementation_name.as_str()) .get(implementation_name.as_str())
.unwrap(); .unwrap_or_else(|| {
let object = DvmObject::new(implementation.clone()); dvm_panic!(
context.registers[*destination_register] = state,
&format!("Cannot find implementation {}", implementation_name)
);
})
.clone();
let object = DvmObject::new(implementation);
state.registers[*destination_register] =
DvmValue::Object(Rc::new(RefCell::new(object))); DvmValue::Object(Rc::new(RefCell::new(object)));
} }
Instruction::InvokeStatic { InvokeStatic {
function_name, function_name,
source_code_location, source_code_location,
} => { } => {
// Find function
let static_function = context let static_function = context
.static_functions .static_functions
.get(function_name.as_str()) .get(function_name.as_str())
.unwrap() .unwrap_or_else(|| {
dvm_panic!(
state,
&format!("Cannot find static function {}", function_name)
);
})
.clone(); .clone();
push_call_frame(function_name.clone(), source_code_location.clone(), context);
run(static_function.instructions(), context); // Do call
pop_call_frame(context); state.stack.push(DvmValue::Empty); // space for return value
push_call_frame(function_name.clone(), source_code_location.clone(), state);
run(static_function.instructions(), state, context);
pop_call_frame(state);
} }
Instruction::InvokeObject { InvokeObject {
object_register, object_register,
function_name, function_name,
source_code_location, source_code_location,
} => { } => {
let object = context.registers[*object_register].expect_object(); // Find method and get instructions
let object_ref = object.borrow(); let object_value = state.registers[*object_register].clone();
let object_rc = object_value.expect_object_or_else(|v| {
dvm_panic!(
state,
&format!("Expected DvmValue::Object, but found {}", object_value)
);
});
let object_ref = object_rc.borrow();
let method = object_ref let method = object_ref
.get_method(function_name.as_str()) .get_method(function_name.as_str())
.expect(&format!( .unwrap_or_else(|| {
"Cannot find method {} for object {:?}", dvm_panic!(
function_name, object state,
)); &format!(
"Cannot find method {} for object {:?}",
function_name, object_ref
)
);
});
let function = method.dm_fn(); let function = method.dm_fn();
let instructions = function.instructions(); let instructions = function.instructions();
push_call_frame(function_name.clone(), source_code_location.clone(), context);
run(instructions, context); // Do call
pop_call_frame(context); state.stack.push(DvmValue::Empty); // space for return value
state.stack.push(object_value); // self object
push_call_frame(function_name.clone(), source_code_location.clone(), state);
run(instructions, state, context);
pop_call_frame(state);
state.stack.pop(); // self object
} }
Instruction::PlatformCall { InvokeStaticPlatform {
platform_function_name, function_name,
source_code_location, source_code_location,
} => { } => {
// Find function
let platform_function = context let platform_function = context
.platform_functions .platform_functions
.get(platform_function_name.as_str()) .get(function_name.as_str())
.unwrap() .unwrap_or_else(|| {
.clone(); dvm_panic!(
push_call_frame( state,
platform_function_name.clone(), &format!("Cannot find static platform function {}", function_name)
source_code_location.clone(), );
context, });
);
platform_function(context); // Do call
pop_call_frame(context); state.stack.push(DvmValue::Empty); // space for return value
push_call_frame(function_name.clone(), source_code_location.clone(), state);
platform_function(state, context);
pop_call_frame(state);
} }
Instruction::Add { .. } => {} InvokeObjectPlatform {
Instruction::Subtract { .. } => {} object_register,
Instruction::Multiply { .. } => {} function_name,
Instruction::Divide { .. } => {} source_code_location,
Instruction::Modulo { .. } => {} } => {
Instruction::Power { .. } => {} // Find function
Instruction::Jump { offset } => { let object_platform_function = context
.platform_functions
.get(function_name.as_str())
.unwrap_or_else(|| {
dvm_panic!(
state,
&format!("Cannot find object platform function {}", function_name)
);
});
// Get self object
let object_value = state.registers[*object_register].clone();
if !object_value.is_object() {
dvm_panic!(
state,
&format!(
"Expected DvmValue::Object, but found DvmValue::{:?}",
object_value
)
);
}
// Do call
state.stack.push(DvmValue::Empty); // space for return value
state.stack.push(object_value); // self object
push_call_frame(function_name.clone(), source_code_location.clone(), state);
object_platform_function(state, context);
pop_call_frame(state);
state.stack.pop(); // self object
}
Add { .. } => {}
Subtract { .. } => {}
Multiply { .. } => {}
Divide { .. } => {}
Modulo { .. } => {}
Power { .. } => {}
Jump { offset } => {
update_index(&mut index, *offset); update_index(&mut index, *offset);
} }
Instruction::JumpEqual { JumpEqual {
left_register, left_register,
right_register, right_register,
offset, offset,
} => { } => {
let left_value = &context.registers[*left_register]; let left_value = &state.registers[*left_register];
let right_value = &context.registers[*right_register]; let right_value = &state.registers[*right_register];
if left_value == right_value { if left_value == right_value {
update_index(&mut index, *offset); update_index(&mut index, *offset);
} }
} }
Instruction::JumpNotEqual { .. } => {} JumpNotEqual { .. } => {}
Instruction::JumpLessThan { .. } => {} JumpLessThan { .. } => {}
Instruction::JumpGreaterThan { .. } => {} JumpGreaterThan { .. } => {}
Instruction::JumpLessThanEqual { .. } => {} JumpLessThanEqual { .. } => {}
Instruction::JumpGreaterThanEqual { .. } => {} JumpGreaterThanEqual { .. } => {}
Instruction::Return => { Return => {
break; break;
} }
} }
index += 1;
} }
} }

View File

@ -4,7 +4,7 @@ use std::collections::HashMap;
mod std_lib; mod std_lib;
pub fn init_platform_functions() -> HashMap<String, PlatformFunction> { pub fn get_std_lib_platform_functions() -> HashMap<String, PlatformFunction> {
let mut fns: HashMap<String, PlatformFunction> = HashMap::new(); let mut fns: HashMap<String, PlatformFunction> = HashMap::new();
fns.insert(String::from("std::core::print"), dm_print); fns.insert(String::from("std::core::print"), dm_print);
fns.insert(String::from("std::core::println"), dm_println); fns.insert(String::from("std::core::println"), dm_println);

View File

@ -1,6 +1,6 @@
use crate::vm::object::DvmObject; use crate::vm::object::DvmObject;
use crate::vm::value::DvmValue; use crate::vm::value::DvmValue;
use crate::vm::DvmContext; use crate::vm::{DvmContext, DvmState};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -8,12 +8,12 @@ use std::rc::Rc;
/// // Signature /// // Signature
/// print(m: &(Byte | Int | Long | Double | USize | Boolean | Object | Empty)) /// print(m: &(Byte | Int | Long | Double | USize | Boolean | Object | Empty))
/// ``` /// ```
pub fn dm_print(context: &mut DvmContext) { pub fn dm_print(state: &mut DvmState, context: &DvmContext) {
print!("{}", get_string(context.pop_stack())); print!("{}", get_string(state.get_stack_argument(0)));
} }
pub fn dm_println(context: &mut DvmContext) { pub fn dm_println(state: &mut DvmState, context: &DvmContext) {
println!("{}", get_string(context.pop_stack())); println!("{}", get_string(state.get_stack_argument(0)));
} }
fn get_string(dvm_value: DvmValue) -> String { fn get_string(dvm_value: DvmValue) -> String {
@ -26,29 +26,11 @@ fn get_string(dvm_value: DvmValue) -> String {
DvmValue::Object(object) => object_to_string(object.clone()), DvmValue::Object(object) => object_to_string(object.clone()),
DvmValue::USize(u) => u.to_string(), DvmValue::USize(u) => u.to_string(),
DvmValue::Array(a) => a.borrow().to_string(), DvmValue::Array(a) => a.borrow().to_string(),
DvmValue::ConstantPointer(p) => p.to_string(), DvmValue::String(s) => s.to_string(),
DvmValue::Empty => String::from("Empty"), DvmValue::Empty => String::from("Empty"),
} }
} }
fn object_to_string(object: Rc<RefCell<DvmObject>>) -> String { fn object_to_string(object: Rc<RefCell<DvmObject>>) -> String {
if object.borrow().implementation().fqn() == "std::core::StringImpl" { todo!("Lookup to_string method!")
extract_string_from_string(object.clone())
} else {
todo!("what happens if we don't have a String?")
}
}
fn extract_string_from_string(string_object: Rc<RefCell<DvmObject>>) -> String {
let object_ref = string_object.borrow();
let bytes_field_value = object_ref.read_field("bytes");
if let DvmValue::ConstantPointer(bytes_ptr) = bytes_field_value {
let mut v = Vec::new();
for i in 0..bytes_ptr.length {
v.push(unsafe { bytes_ptr.raw_pointer.add(i).read() });
}
String::from_utf8(v).unwrap()
} else {
panic!("StringImpl.bytes field is not a DvmValue::ConstantPointer.");
}
} }

View File

@ -1,13 +0,0 @@
use std::fmt::Display;
#[derive(Debug, Clone, PartialEq)]
pub struct DvmPointer {
pub raw_pointer: *const u8,
pub length: usize,
}
impl Display for DvmPointer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "DvmPointer({:p}, {})", self.raw_pointer, self.length)
}
}

View File

@ -0,0 +1,6 @@
#[derive(Debug, Clone)]
pub struct SourceCodeLocation {
pub source_file_name: String,
pub line: i64,
pub char: i64,
}

View File

@ -1,6 +1,5 @@
use crate::vm::array::DvmArray; use crate::vm::array::DvmArray;
use crate::vm::object::DvmObject; use crate::vm::object::DvmObject;
use crate::vm::pointer::DvmPointer;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::rc::Rc; use std::rc::Rc;
@ -21,8 +20,8 @@ pub enum DvmValue {
// Array // Array
Array(Rc<RefCell<DvmArray>>), Array(Rc<RefCell<DvmArray>>),
// Pointer to constant u8 // String
ConstantPointer(DvmPointer), String(Rc<String>),
// Null // Null
Empty, Empty,
@ -45,7 +44,7 @@ impl Display for DvmValue {
DvmValue::Boolean(b) => write!(f, "Boolean({})", b), DvmValue::Boolean(b) => write!(f, "Boolean({})", b),
DvmValue::Object(o) => write!(f, "Object({:p})", &o), DvmValue::Object(o) => write!(f, "Object({:p})", &o),
DvmValue::Array(a) => write!(f, "Array({:p})", &a), DvmValue::Array(a) => write!(f, "Array({:p})", &a),
DvmValue::ConstantPointer(p) => write!(f, "ConstantPointer({})", p), DvmValue::String(s) => write!(f, "String({})", s),
DvmValue::Empty => write!(f, "Empty"), DvmValue::Empty => write!(f, "Empty"),
} }
} }
@ -71,6 +70,14 @@ impl DvmValue {
panic!("Expected DvmValue::Int, but found DvmValue::{:?}", self); panic!("Expected DvmValue::Int, but found DvmValue::{:?}", self);
} }
} }
pub fn expect_int_or_else(&self, f: impl FnOnce(&Self) -> i32) -> i32 {
if let DvmValue::Int(i) = self {
*i
} else {
f(self)
}
}
pub fn expect_long(&self) -> i64 { pub fn expect_long(&self) -> i64 {
if let DvmValue::Long(l) = self { if let DvmValue::Long(l) = self {
@ -103,6 +110,17 @@ impl DvmValue {
} }
} }
pub fn expect_object_or_else(
&self,
f: impl FnOnce(&Self) -> DvmObject,
) -> Rc<RefCell<DvmObject>> {
if let DvmValue::Object(o) = self {
o.clone()
} else {
Rc::new(RefCell::new(f(self)))
}
}
pub fn map_object<T>( pub fn map_object<T>(
&self, &self,
mapper: impl FnOnce(Rc<RefCell<DvmObject>>) -> T, mapper: impl FnOnce(Rc<RefCell<DvmObject>>) -> T,
@ -136,7 +154,7 @@ impl DvmValue {
_ => false, _ => false,
} }
} }
pub fn map_array<T>( pub fn map_array<T>(
&self, &self,
mapper: impl FnOnce(Rc<RefCell<DvmArray>>) -> T, mapper: impl FnOnce(Rc<RefCell<DvmArray>>) -> T,
@ -183,14 +201,19 @@ impl DvmValue {
} }
} }
pub fn expect_constant_pointer(&self) -> DvmPointer { pub fn expect_string(&self) -> Rc<String> {
if let DvmValue::ConstantPointer(ptr) = self { if let DvmValue::String(s) = self {
ptr.clone() s.clone()
} else { } else {
panic!( panic!("Expected DvmValue::String, but found DvmValue::{:?}", self);
"Expected DvmValue::ConstantPointer, but found DvmValue::{:?}", }
self }
);
pub fn expect_string_or_else(&self, f: impl FnOnce(&Self) -> String) -> Rc<String> {
if let DvmValue::String(s) = self {
s.clone()
} else {
Rc::new(f(self))
} }
} }
} }