Compare commits

..

No commits in common. "cf0c44e627a3d2520ff3fe9ea04f9ff741dfd364" and "652c1dd7f2d2992d2b1bdbb90aa02ee793e2deac" have entirely different histories.

11 changed files with 461 additions and 246 deletions

View File

@ -91,7 +91,7 @@ The operand is converted to a `bool` at runtime by the virtual machine.
=== Move Register === Move Register
Moves or copies (see below) the value in one register to another. Copies the value in one register to another.
[source] [source]
---- ----
@ -101,12 +101,60 @@ mov_register(
) )
---- ----
For `Byte`, `Int`, `Long`, `USize`, `Double`, and `Boolean`, the value is **copied** to the register. For `Object` === Load Byte
values, the value is **moved**, meaning that register takes ownership of the referenced object.
=== Load Loads the target register with the `u8` stored at the offset from the base of the object stored in the source register.
Loads the target register with the `DvmValue` inner value stored in the field at `field_index` in the object in the [source]
----
load_byte(
target_register: u8,
source_register: u8,
offset: usize
)
----
The source register must contain a `DvmValue::Object` at runtime.
=== Load Int
Loads the target register with the `i32` stored at the offset from the base of the object stored in the source register.
[source]
----
load_int(
target_register: u8,
source_register: u8,
offset: usize
)
----
The source register must contain a `DvmValue::Object` at runtime.
=== Load Long
Loads the target register with the `i64` stored at the offset from the base of the object stored in the source register.
[source]
----
load_long(
target_register: u8,
source_register: u8,
offset: usize
)
----
The source register must contain a `DvmValue::Object` at runtime.
=== Load Double
=== Load USize
=== Load Boolean
=== Load Object
Loads the target register with the `DvmValue::Object` stored at the offset from the base of the object stored in the
source register. source register.
[source] [source]
@ -114,15 +162,16 @@ source register.
load_object( load_object(
target_register: u8, target_register: u8,
source_register: u8, source_register: u8,
field_index: usize offset: usize
) )
---- ----
The source register must contain a `DvmValue::Object` at runtime. The source register must contain a `DvmValue::Object` at runtime, and the data at the offset from that object's base
must be a valid `Rc<DvmObject>`.
=== Store === Store
Stores the value contained in the source register to the field at `field_index` in the object contained in the target Stores the value contained in the source register to the offset from the base of the object contained in the target
register. register.
[source] [source]

View File

@ -2,7 +2,7 @@ use deimos::vm::dm_type::DmType;
use deimos::vm::lib::{DmConstant, DmLib}; use deimos::vm::lib::{DmConstant, DmLib};
use deimos::vm::object_type::{DmField, DmFn, DmImplementation, DmInterface, DmMethod}; use deimos::vm::object_type::{DmField, DmFn, DmImplementation, DmInterface, DmMethod};
use deimos::vm::op_codes::{ use deimos::vm::op_codes::{
add_alloc, add_dealloc, add_invoke_fn, add_mov_const, add_platform_call, add_store, 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::platform::init_platform_functions;
use deimos::vm::{call_fn, DvmContext, DvmState}; use deimos::vm::{call_fn, DvmContext, DvmState};
@ -28,9 +28,9 @@ fn main() {
Some(array_int_rc.clone()), Some(array_int_rc.clone()),
); );
let array_impl_ptr_address_fld = DmField::new("ptr_address", DmType::USize); 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); let array_impl_ptr_size_fld = DmField::new("ptr_size", DmType::USize, 8);
let array_impl_length_fld = DmField::new("length", DmType::Long); let array_impl_length_fld = DmField::new("length", DmType::Long, 16);
array_impl.fields.push(array_impl_ptr_address_fld); array_impl.fields.push(array_impl_ptr_address_fld);
array_impl.fields.push(array_impl_ptr_size_fld); array_impl.fields.push(array_impl_ptr_size_fld);
@ -44,9 +44,9 @@ fn main() {
// ) // )
let mut array_impl_ctor_0_bytecode: Vec<u8> = Vec::new(); let mut array_impl_ctor_0_bytecode: Vec<u8> = Vec::new();
add_store(&mut array_impl_ctor_0_bytecode, 0, 0, 1); add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 0, 1);
add_store(&mut array_impl_ctor_0_bytecode, 0, 1, 2); add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 8, 2);
add_store(&mut array_impl_ctor_0_bytecode, 0, 2, 3); add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 16, 3);
let array_impl_ctor_0_fn = DmFn::new( let array_impl_ctor_0_fn = DmFn::new(
"std::core::ArrayImpl::_ctor_0", "std::core::ArrayImpl::_ctor_0",
@ -70,7 +70,7 @@ fn main() {
let mut string_impl = DmImplementation::new("std::core::StringImpl", "StringImpl", None); let mut string_impl = DmImplementation::new("std::core::StringImpl", "StringImpl", None);
let bytes_field = DmField::new("bytes", DmType::Object); let bytes_field = DmField::new("bytes", DmType::Object, 0);
string_impl.fields.push(bytes_field); string_impl.fields.push(bytes_field);
// std::core::String::_ctor_0( // std::core::String::_ctor_0(
@ -78,7 +78,7 @@ fn main() {
// r1: Array<Byte> bytes // r1: Array<Byte> bytes
// ) // )
let mut string_ctor_0_bytecode: Vec<u8> = Vec::new(); let mut string_ctor_0_bytecode: Vec<u8> = Vec::new();
add_store(&mut string_ctor_0_bytecode, 0, 0, 1); add_mov_register_to(&mut string_ctor_0_bytecode, 0, 0, 1);
let string_ctor_0_fn = DmFn::new( let string_ctor_0_fn = DmFn::new(
"std::core::StringImpl::_ctor_0", "std::core::StringImpl::_ctor_0",
@ -91,6 +91,7 @@ fn main() {
let string_ctor_0_method = DmMethod::new(string_ctor_0_fn, None); let string_ctor_0_method = DmMethod::new(string_ctor_0_fn, None);
string_impl.methods.push(Rc::new(string_ctor_0_method)); string_impl.methods.push(Rc::new(string_ctor_0_method));
let core_string_impl_size = string_impl.size_in_bytes();
string_lib.interfaces.push(Rc::new(string_int)); string_lib.interfaces.push(Rc::new(string_int));
string_lib.implementations.push(Rc::new(string_impl)); string_lib.implementations.push(Rc::new(string_impl));
@ -109,7 +110,12 @@ fn main() {
add_mov_const(&mut main_byte_code, 0, 1, "greeting", 0); add_mov_const(&mut main_byte_code, 0, 1, "greeting", 0);
// Alloc Array<Byte> greeting bytes // Alloc Array<Byte> greeting bytes
add_alloc(&mut main_byte_code, 2, "std::core::ArrayImpl"); add_alloc(
&mut main_byte_code,
2,
array_impl_rc.size_in_bytes() as u32,
"std::core::ArrayImpl",
);
// Call ArrayImpl(ptr_address, ptr_size, length) // Call ArrayImpl(ptr_address, ptr_size, length)
add_invoke_fn( add_invoke_fn(
@ -120,7 +126,12 @@ fn main() {
); );
// Alloc StringImpl greeting // Alloc StringImpl greeting
add_alloc(&mut main_byte_code, 4, "std::core::StringImpl"); add_alloc(
&mut main_byte_code,
4,
core_string_impl_size as u32,
"std::core::StringImpl",
);
// Call StringImpl(greeting_bytes) // Call StringImpl(greeting_bytes)
add_invoke_fn( add_invoke_fn(
@ -133,12 +144,6 @@ fn main() {
// Call println(greeting) // Call println(greeting)
add_platform_call(&mut main_byte_code, "std::core::println", 6, &[4]); 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 = DmFn::new("main", "main", main_byte_code, 7, None); let main_dm_fn = DmFn::new("main", "main", main_byte_code, 7, None);
greeting_lib.functions.push(Rc::new(main_dm_fn)); greeting_lib.functions.push(Rc::new(main_dm_fn));

View File

@ -7,6 +7,7 @@ pub enum DmType {
Boolean, Boolean,
Object, Object,
USize, USize,
Unit,
} }
impl DmType { impl DmType {
@ -19,6 +20,7 @@ impl DmType {
DmType::Boolean => size_of::<bool>(), DmType::Boolean => size_of::<bool>(),
DmType::Object => size_of::<usize>(), DmType::Object => size_of::<usize>(),
DmType::USize => 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::object::DvmObject; use crate::vm::object::DmAllocObject;
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -8,7 +8,7 @@ pub enum DvmValue {
Long(i64), Long(i64),
Double(f64), Double(f64),
Boolean(bool), Boolean(bool),
Object(Rc<DvmObject>), Object(Rc<DmAllocObject>),
USize(usize), USize(usize),
Uninit, Uninit,
Void, Void,
@ -23,7 +23,7 @@ impl DvmValue {
} }
} }
pub fn expect_object(&self) -> Rc<DvmObject> { pub fn expect_object(&self) -> Rc<DmAllocObject> {
if let DvmValue::Object(o) = self { if let DvmValue::Object(o) = self {
o.clone() o.clone()
} else { } else {
@ -31,13 +31,6 @@ impl DvmValue {
} }
} }
pub fn is_object(&self) -> bool {
match self {
DvmValue::Object(_) => true,
_ => false,
}
}
pub fn expect_usize(&self) -> usize { pub fn expect_usize(&self) -> usize {
if let DvmValue::USize(u) = self { if let DvmValue::USize(u) = self {
*u *u

View File

@ -1,86 +1,70 @@
use crate::vm::dm_type::DmType; use crate::vm::dm_type::DmType;
use crate::vm::dvm_value::DvmValue; use crate::vm::dvm_value::DvmValue;
use crate::vm::object::DvmObject; use crate::vm::object::DmAllocObject;
use crate::vm::object_type::DmField;
use std::rc::Rc; use std::rc::Rc;
unsafe fn read_field(data_pointer: *const u8, dm_type: &DmType) -> DvmValue { pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -> DvmValue {
match dm_type { let data_size = dm_field.dm_type().size_in_bytes();
DmType::Byte => DvmValue::Byte(data_pointer.read()), let mut raw_data: Vec<u8> = Vec::with_capacity(data_size);
DmType::Int => DvmValue::Int(data_pointer.cast::<i32>().read()), for i in dm_field.data_offset()..(dm_field.data_offset() + data_size) {
DmType::Long => DvmValue::Long(data_pointer.cast::<i64>().read()), raw_data.push(self_object.data.offset(i as isize).read());
DmType::USize => DvmValue::USize(data_pointer.cast::<usize>().read()), }
DmType::Double => DvmValue::Double(data_pointer.cast::<f64>().read()), match dm_field.dm_type() {
DmType::Boolean => DvmValue::Boolean(data_pointer.cast::<bool>().read()), DmType::Byte => DvmValue::Byte(raw_data[0]),
DmType::Object => DvmValue::Object(data_pointer.cast::<Rc<DvmObject>>().read()), DmType::Int => DvmValue::Int(i32::from_ne_bytes(
raw_data[0..data_size].try_into().unwrap(),
)),
DmType::Long => DvmValue::Long(i64::from_ne_bytes(
raw_data[0..data_size].try_into().unwrap(),
)),
DmType::Double => DvmValue::Double(f64::from_ne_bytes(
raw_data[0..data_size].try_into().unwrap(),
)),
DmType::Boolean => DvmValue::Boolean(raw_data[0] != 0),
DmType::Object => {
// read the pointer's (address) value
let address = usize::from_ne_bytes(raw_data[0..data_size].try_into().unwrap());
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,
} }
} }
pub fn read_field_by_name(field_name: &str, self_object: &DvmObject) -> DvmValue { macro_rules! read_array {
let (field_index, field) = self_object ( $T: ty, $raw_data: expr, $length: expr ) => {{
.implementation() let t_size = size_of::<$T>();
.fields let mut arr: Vec<$T> = Vec::with_capacity($length);
.iter() for i in 0..$length {
.enumerate() arr.push(<$T>::from_ne_bytes(
.find(|(_index, field)| field.name() == field_name) $raw_data[(i * t_size)..(i * t_size + t_size)]
.expect(&format!( .try_into()
"Cannot find field {} in {}", .unwrap(),
field_name, ))
self_object.implementation().fqn }
)); arr
let data_pointer = self_object.data()[field_index]; }};
unsafe { read_field(data_pointer, field.dm_type()) }
} }
pub fn read_field_by_index(index: usize, self_object: &DvmObject) -> DvmValue { fn read_i32_array(raw_data: &Vec<u8>, length: usize) -> Vec<i32> {
let field = &self_object.implementation().fields[index]; read_array!(i32, raw_data, length)
let data_pointer = self_object.data()[index];
unsafe { read_field(data_pointer, field.dm_type()) }
} }
unsafe fn write_field(data_pointer: *mut u8, value: DvmValue) { fn read_i64_array(raw_data: &Vec<u8>, length: usize) -> Vec<i64> {
match value { read_array!(i64, raw_data, length)
DvmValue::Byte(b) => {
data_pointer.write(b);
}
DvmValue::Int(i) => {
data_pointer.cast::<i32>().write(i);
}
DvmValue::Long(l) => {
data_pointer.cast::<i64>().write(l);
}
DvmValue::USize(u) => {
data_pointer.cast::<usize>().write(u);
}
DvmValue::Double(d) => {
data_pointer.cast::<f64>().write(d);
}
DvmValue::Boolean(b) => {
data_pointer.cast::<bool>().write(b);
}
DvmValue::Object(o) => {
data_pointer.cast::<Rc<DvmObject>>().write(o);
}
DvmValue::Uninit => panic!("Cannot write DvmValue::Uninit to field."),
DvmValue::Void => panic!("Cannot write DvmValue::Void to field."),
}
} }
pub fn write_field_by_name(field_name: &str, self_object: &DvmObject, value: DvmValue) { fn read_f64_array(raw_data: &Vec<u8>, length: usize) -> Vec<f64> {
let field_index = self_object read_array!(f64, raw_data, length)
.implementation()
.fields
.iter()
.position(|field| field.name() == field_name)
.expect(&format!(
"Cannot find field {} in {}",
field_name,
self_object.implementation().fqn
));
let data_pointer = self_object.data()[field_index];
unsafe { write_field(data_pointer, value) };
} }
pub fn write_field_by_index(index: usize, self_object: &DvmObject, value: DvmValue) { fn read_bool_array(raw_data: &Vec<u8>) -> Vec<bool> {
let data_pointer = self_object.data()[index]; raw_data.iter().map(|b| *b == 1).collect()
unsafe { write_field(data_pointer, value) }; }
fn read_usize_array(raw_data: &Vec<u8>, length: usize) -> Vec<usize> {
read_array!(usize, raw_data, length)
} }

View File

@ -11,8 +11,7 @@ pub mod util;
use crate::vm::dvm_value::DvmValue; use crate::vm::dvm_value::DvmValue;
use crate::vm::lib::{DmConstant, DmLib}; use crate::vm::lib::{DmConstant, DmLib};
use crate::vm::mem::{read_field_by_index, write_field_by_index}; use crate::vm::object::DmAllocObject;
use crate::vm::object::DvmObject;
use crate::vm::object_type::DmFn; use crate::vm::object_type::DmFn;
use op_codes::*; use op_codes::*;
use std::alloc::{alloc, dealloc, Layout}; use std::alloc::{alloc, dealloc, Layout};
@ -274,9 +273,6 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
let mut iter = byte_code.iter().cloned(); let mut iter = byte_code.iter().cloned();
while let Some(op_code) = iter.next() { while let Some(op_code) = iter.next() {
match op_code { match op_code {
MOV_BYTE => {
todo!()
}
MOV_INT => { MOV_INT => {
let target_register = next_8!(iter, usize); let target_register = next_8!(iter, usize);
let operand = next_32_le!(iter, u32) as i32; let operand = next_32_le!(iter, u32) as i32;
@ -298,37 +294,73 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
let source_value = state.registers.get(source_register).unwrap(); let source_value = state.registers.get(source_register).unwrap();
state.registers[target_register] = source_value.clone(); state.registers[target_register] = source_value.clone();
} }
LOAD => { LOAD_OBJECT => {
let target_register = next_8!(iter, usize); let target_register = next_8!(iter, usize);
let source_register = next_8!(iter, usize); let source_register = next_8!(iter, usize);
let source_object_field_index = next_usize_le!(iter); let offset = next_usize_le!(iter);
let source_object = state let source_object = state.registers
.registers
.get(source_register) .get(source_register)
.unwrap() .unwrap()
.expect_object(); .expect_object();
state.registers[target_register] = let object = unsafe {
read_field_by_index(source_object_field_index, &source_object); Rc::from_raw(source_object.data.add(offset).cast::<DmAllocObject>())
};
state.registers[target_register] = DvmValue::Object(object);
} }
STORE => { STORE => {
let target_register = next_8!(iter, usize); let target_register = next_8!(iter, usize);
let target_object_field_index = next_usize_le!(iter); let offset = next_usize_le!(iter);
let source_register = next_8!(iter, usize); let source_register = next_8!(iter, usize);
let target_object = state let target_alloc_object = state
.registers .registers
.get(target_register) .get(target_register)
.unwrap() .unwrap()
.expect_object(); .expect_object();
let source_value = let source_value = std::mem::replace(&mut state.registers[source_register], DvmValue::Uninit);
std::mem::replace(&mut state.registers[source_register], DvmValue::Uninit);
write_field_by_index(target_object_field_index, &target_object, source_value); match source_value {
DvmValue::Int(i) => {
write_bytes!(target_alloc_object.data, offset, i.to_ne_bytes());
}
DvmValue::Byte(b) => unsafe {
target_alloc_object.data.add(offset).write(b);
},
DvmValue::Long(l) => {
write_bytes!(target_alloc_object.data, offset, l.to_ne_bytes());
}
DvmValue::Double(d) => {
write_bytes!(target_alloc_object.data, offset, d.to_ne_bytes());
}
DvmValue::Boolean(b) => unsafe {
target_alloc_object.data.add(offset).write(b as u8);
},
DvmValue::Object(source_object) => {
let source_object_ptr = Rc::into_raw(source_object);
write_bytes!(
target_alloc_object.data,
offset,
(source_object_ptr as usize).to_ne_bytes()
);
}
DvmValue::USize(u) => {
write_bytes!(target_alloc_object.data, offset, u.to_ne_bytes());
}
DvmValue::Uninit => {
panic!("Cannot store DvmValue::Uninit to object.")
}
DvmValue::Void => {
panic!("Cannot store DvmValue::Void to object.")
}
}
} }
ALLOC => { ALLOC => {
let target_register = next_8!(iter, usize); let target_register = next_8!(iter, usize);
let alloc_size = next_32_le!(iter, usize);
let impl_name = read_string!(iter); let impl_name = read_string!(iter);
let implementation = context let implementation = context
@ -341,19 +373,86 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
}) })
.expect(&format!("Implementation not found: {}", impl_name)); .expect(&format!("Implementation not found: {}", impl_name));
let dm_alloc_object = DvmObject::new(implementation.clone()); let dm_alloc_object = DmAllocObject::new(alloc_size, implementation.clone());
state.registers[target_register] = DvmValue::Object(Rc::new(dm_alloc_object)); state.registers[target_register] = DvmValue::Object(Rc::new(dm_alloc_object));
} }
DEALLOC => { DEALLOC => {
let target_register = next_8!(iter, usize); let target_register = next_8!(iter, usize);
let dvm_object = state let dm_alloc_object = state
.registers .registers
.get(target_register) .get(target_register)
.unwrap() .unwrap()
.expect_object(); .expect_object();
drop(dvm_object); // explicit drop(dm_alloc_object); // explicit
state.registers[target_register] = DvmValue::Uninit; state.registers[target_register] = DvmValue::Uninit;
} }
MOV_INT_TO => {
let target_register = next_8!(iter, usize);
let offset = next_32_le!(iter, usize);
let operand = next_32_le!(iter, u32) as i32;
let dm_alloc_object = state
.registers
.get(target_register)
.unwrap()
.expect_object();
write_bytes!(dm_alloc_object.data, offset, operand.to_ne_bytes());
}
MOV_LONG_TO => {
todo!()
}
MOV_DOUBLE_TO => {
todo!()
}
MOV_REGISTER_TO => {
// Moves the value from the source register to the object pointed to by the target
// register, at the given offset.
let target_register = next_8!(iter, usize);
let offset = next_32_le!(iter, usize);
let source_register = next_8!(iter, usize);
let target_alloc_object = state
.registers
.get(target_register)
.unwrap()
.expect_object();
let source_value = state.registers.get(source_register).unwrap();
match source_value {
DvmValue::Int(i) => {
write_bytes!(target_alloc_object.data, offset, i.to_ne_bytes());
}
DvmValue::Byte(b) => unsafe {
target_alloc_object.data.add(offset).write(*b);
},
DvmValue::Long(l) => {
write_bytes!(target_alloc_object.data, offset, l.to_ne_bytes());
}
DvmValue::Double(d) => {
write_bytes!(target_alloc_object.data, offset, d.to_ne_bytes());
}
DvmValue::Boolean(b) => unsafe {
target_alloc_object.data.add(offset).write(*b as u8);
},
DvmValue::Object(source_object) => {
let source_object_ptr = Rc::into_raw(source_object.clone());
write_bytes!(
target_alloc_object.data,
offset,
(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.")
}
DvmValue::Void => {
panic!("Cannot move DvmValue::Void to object.")
}
}
}
MOV_CONST => { MOV_CONST => {
// Decode // Decode
let address_register = next_8!(iter, usize); let address_register = next_8!(iter, usize);
@ -465,7 +564,7 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
let self_obj = args.get(0).unwrap().expect_object(); let self_obj = args.get(0).unwrap().expect_object();
let method = self_obj let method = self_obj
.implementation() .implementation
.get_method(&symbol_name, &self_obj) .get_method(&symbol_name, &self_obj)
.expect(&format!("Could not find method: {}", symbol_name)); .expect(&format!("Could not find method: {}", symbol_name));
let dm_fn = method.dm_fn(); let dm_fn = method.dm_fn();
@ -476,6 +575,9 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
INVOKE_DYNAMIC => { INVOKE_DYNAMIC => {
unimplemented!("INVOKE_DYNAMIC is not yet supported and may never be.") unimplemented!("INVOKE_DYNAMIC is not yet supported and may never be.")
} }
MOV_SIZE_OF => {
todo!()
}
MULTIPLY => { MULTIPLY => {
todo!() todo!()
} }
@ -488,9 +590,9 @@ pub fn run_byte_code(state: &mut DvmState, context: &DvmContext, byte_code: &[u8
#[cfg(test)] #[cfg(test)]
mod run_code_tests { mod run_code_tests {
use super::*;
use crate::vm::dm_type::DmType; use crate::vm::dm_type::DmType;
use crate::vm::object_type::{DmField, DmImplementation}; use crate::vm::object_type::{DmField, DmImplementation};
use super::*;
macro_rules! assert_register { macro_rules! assert_register {
( $expected: expr, $state: expr, $register_number: expr ) => { ( $expected: expr, $state: expr, $register_number: expr ) => {
@ -501,17 +603,13 @@ mod run_code_tests {
}; };
} }
fn setup(number_of_registers: usize) -> (DvmState, DvmContext) { fn setup() -> (DvmState, DvmContext) {
let mut state = DvmState::new(); (DvmState::new(), DvmContext::new())
state
.registers
.resize(number_of_registers, DvmValue::Uninit);
(state, DvmContext::new())
} }
fn impl_with_object_field() -> DmImplementation { fn impl_with_object_field() -> DmImplementation {
let mut dm_impl = DmImplementation::new("ImplWithObjectField", "ImplWithObjectField", None); let mut dm_impl = DmImplementation::new("ImplWithObjectField", "ImplWithObjectField", None);
let object_field = DmField::new("object_field", DmType::Object); let object_field = DmField::new("object_field", DmType::Object, 0);
dm_impl.fields.push(object_field); dm_impl.fields.push(object_field);
dm_impl dm_impl
} }
@ -520,7 +618,7 @@ mod run_code_tests {
fn mov_1_as_int() { fn mov_1_as_int() {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 0, 1); add_mov_int(&mut code, 0, 1);
let (mut state, context) = setup(1); let (mut state, context) = setup();
run_byte_code(&mut state, &context, &code); run_byte_code(&mut state, &context, &code);
assert_register!(DvmValue::Int(1), state, 0); assert_register!(DvmValue::Int(1), state, 0);
} }
@ -529,7 +627,7 @@ mod run_code_tests {
fn move_65535_as_int() { fn move_65535_as_int() {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 0, 0xffff); add_mov_int(&mut code, 0, 0xffff);
let (mut state, context) = setup(1); let (mut state, context) = setup();
run_byte_code(&mut state, &context, &code); run_byte_code(&mut state, &context, &code);
assert_register!(DvmValue::Int(0xffff), state, 0); assert_register!(DvmValue::Int(0xffff), state, 0);
} }
@ -538,7 +636,7 @@ mod run_code_tests {
fn move_int_max_as_int() { fn move_int_max_as_int() {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 0, 0x0fff_ffff); add_mov_int(&mut code, 0, 0x0fff_ffff);
let (mut state, context) = setup(1); let (mut state, context) = setup();
run_byte_code(&mut state, &context, &code); run_byte_code(&mut state, &context, &code);
assert_register!(DvmValue::Int(0x0fff_ffff), state, 0); assert_register!(DvmValue::Int(0x0fff_ffff), state, 0);
} }
@ -548,7 +646,8 @@ mod run_code_tests {
let mut code = Vec::new(); let mut code = Vec::new();
add_mov_int(&mut code, 1, 1); add_mov_int(&mut code, 1, 1);
add_mov_register(&mut code, 0, 1); add_mov_register(&mut code, 0, 1);
let (mut state, context) = setup(2); let (mut state, context) = setup();
state.registers.resize(2, DvmValue::Uninit);
run_byte_code(&mut state, &context, &code); run_byte_code(&mut state, &context, &code);
assert_register!(DvmValue::Int(1), state, 0); assert_register!(DvmValue::Int(1), state, 0);
} }
@ -557,20 +656,24 @@ mod run_code_tests {
fn load_object() { fn load_object() {
let dummy_impl = impl_with_object_field(); let dummy_impl = impl_with_object_field();
let dummy_impl_rc = Rc::new(dummy_impl); let dummy_impl_rc = Rc::new(dummy_impl);
let dummy_impl_object_field = dummy_impl_rc.fields.iter().find(|field| {
field.name() == "object_field"
}).unwrap();
let mut dummy_lib = DmLib::new("dummy"); let mut dummy_lib = DmLib::new("dummy");
dummy_lib.implementations.push(dummy_impl_rc.clone()); dummy_lib.implementations.push(dummy_impl_rc.clone());
let mut code = Vec::new(); let mut code = Vec::new();
add_alloc(&mut code, 0, &dummy_impl_rc.fqn); add_alloc(&mut code, 0, dummy_impl_rc.size_in_bytes() as u32, &dummy_impl_rc.fqn);
add_alloc(&mut code, 1, &dummy_impl_rc.fqn); add_alloc(&mut code, 1, dummy_impl_rc.size_in_bytes() as u32, &dummy_impl_rc.fqn);
add_store(&mut code, 0, 0, 1); add_store(&mut code, 0, dummy_impl_object_field.data_offset(), 1);
add_load(&mut code, 2, 0, 0); add_load_object(&mut code, 2, 0, dummy_impl_object_field.data_offset());
let (mut state, mut context) = setup(3); let (mut state, mut context) = setup();
state.registers.resize(3, DvmValue::Uninit); state.registers.resize(3, DvmValue::Uninit);
context.load_libs(vec![Rc::new(dummy_lib)]); context.load_libs(vec![Rc::new(dummy_lib)]);
run_byte_code(&mut state, &context, &code); run_byte_code(&mut state, &context, &code);
assert!(state.registers[2].is_object()) let referenced_object = state.registers.get(1).unwrap().expect_object();
assert_register!(DvmValue::Object(referenced_object), state, 2);
} }
} }

View File

@ -1,52 +1,34 @@
use crate::vm::dm_type::DmType;
use crate::vm::object_type::DmImplementation; use crate::vm::object_type::DmImplementation;
use std::alloc::{alloc, dealloc, Layout}; use std::alloc::{alloc, dealloc, Layout};
use std::ptr; use std::collections::HashSet;
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct DvmObject { pub struct DmAllocObject {
data: Vec<*mut u8>, pub data: *mut u8,
implementation: Rc<DmImplementation>, pub units: HashSet<usize>,
pub size: usize,
pub layout: Layout,
pub implementation: Rc<DmImplementation>,
} }
fn layout_for(dm_type: &DmType) -> Layout { impl DmAllocObject {
match dm_type { pub fn new(size: usize, implementation: Rc<DmImplementation>) -> Self {
DmType::Byte => Layout::new::<u8>(), let layout = Layout::from_size_align(size, 1).unwrap();
DmType::Int => Layout::new::<i32>(), DmAllocObject {
DmType::Long => Layout::new::<i64>(), data: unsafe { alloc(layout) },
DmType::USize => Layout::new::<usize>(), units: HashSet::new(),
DmType::Double => Layout::new::<f64>(), size,
DmType::Boolean => Layout::new::<bool>(), layout,
DmType::Object => Layout::new::<Rc<DvmObject>>(),
}
}
impl DvmObject {
pub fn new(implementation: Rc<DmImplementation>) -> Self {
let mut data = vec![ptr::null_mut(); implementation.fields.len()];
for (index, field) in implementation.fields.iter().enumerate() {
data[index] = unsafe { alloc(layout_for(field.dm_type())) }
}
DvmObject {
data,
implementation, implementation,
} }
} }
pub fn data(&self) -> &[*mut u8] {
&self.data
}
pub fn implementation(&self) -> &DmImplementation {
&self.implementation
}
} }
impl Drop for DvmObject { impl Drop for DmAllocObject {
fn drop(&mut self) { fn drop(&mut self) {
for (index, field) in self.implementation.fields.iter().enumerate() { unsafe {
unsafe { dealloc(self.data[index], layout_for(field.dm_type())) } dealloc(self.data, self.layout);
} }
} }
} }

View File

@ -1,5 +1,5 @@
use crate::vm::dm_type::DmType; use crate::vm::dm_type::DmType;
use crate::vm::object::DvmObject; use crate::vm::object::DmAllocObject;
use std::fmt::Debug; use std::fmt::Debug;
use std::rc::Rc; use std::rc::Rc;
@ -131,14 +131,14 @@ impl DmInterface {
self.virtual_methods.push(Rc::new(dm_virtual_method)); self.virtual_methods.push(Rc::new(dm_virtual_method));
} }
pub fn get_method(&self, name: &str, self_object: &DvmObject) -> Option<Rc<DmMethod>> { pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmMethod>> {
if self if self
.virtual_methods .virtual_methods
.iter() .iter()
.find(|&dm_fn| dm_fn.fqn == name) .find(|&dm_fn| dm_fn.fqn == name)
.is_some() .is_some()
{ {
return self_object.implementation().get_method(name, self_object); return self_object.implementation.get_method(name, self_object);
} }
None None
} }
@ -147,7 +147,7 @@ impl DmInterface {
self.virtual_methods.clone() self.virtual_methods.clone()
} }
pub fn get_property(&self, name: &str, self_object: &DvmObject) -> Option<&DmProperty> { pub fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmProperty> {
todo!() todo!()
} }
} }
@ -196,7 +196,7 @@ impl DmImplementation {
self.interface.clone() self.interface.clone()
} }
pub fn get_method(&self, name: &str, self_object: &DvmObject) -> Option<Rc<DmMethod>> { pub fn get_method(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmMethod>> {
for method in &self.methods { for method in &self.methods {
if method.dm_fn.fqn == name { if method.dm_fn.fqn == name {
return Some(method.clone()); return Some(method.clone());
@ -209,13 +209,17 @@ impl DmImplementation {
None None
} }
pub fn get_property(&self, name: &str, self_object: &DvmObject) -> Option<Rc<DmProperty>> { pub fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmProperty>> {
todo!() todo!()
} }
pub fn get_field(&self, name: &str, self_object: &DvmObject) -> Option<&DmField> { pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmField> {
self.fields.iter().find(|field| field.name == name) self.fields.iter().find(|field| field.name == name)
} }
pub fn size_in_bytes(&self) -> usize {
self.fields.iter().map(|field| field.size_in_bytes()).sum()
}
} }
#[derive(Debug, Eq)] #[derive(Debug, Eq)]
@ -235,6 +239,7 @@ impl PartialEq for DmProperty {
pub struct DmField { pub struct DmField {
name: String, name: String,
dm_type: DmType, dm_type: DmType,
data_offset: usize,
} }
impl PartialEq for DmField { impl PartialEq for DmField {
@ -244,10 +249,11 @@ impl PartialEq for DmField {
} }
impl DmField { impl DmField {
pub fn new(name: &str, dm_type: DmType) -> Self { pub fn new(name: &str, dm_type: DmType, data_offset: usize) -> Self {
DmField { DmField {
name: name.to_string(), name: name.to_string(),
dm_type, dm_type,
data_offset,
} }
} }
@ -258,4 +264,12 @@ impl DmField {
pub fn dm_type(&self) -> &DmType { pub fn dm_type(&self) -> &DmType {
&self.dm_type &self.dm_type
} }
pub fn data_offset(&self) -> usize {
self.data_offset
}
pub fn size_in_bytes(&self) -> usize {
self.dm_type.size_in_bytes()
}
} }

View File

@ -1,39 +1,59 @@
pub const MOV_BYTE: u8 = 0x01; use crate::push_bytes;
pub const MOV_INT: u8 = 0x02;
pub const MOV_LONG: u8 = 0x03;
pub const MOV_U_SIZE: u8 = 0x04;
pub const MOV_DOUBLE: u8 = 0x05;
pub const MOV_BOOLEAN: u8 = 0x06;
pub const MOV_REGISTER: u8 = 0x07;
pub const MOV_CONST: u8 = 0x08;
pub const LOAD: u8 = 0x10; /// ## mov(register: u8, operand: u32)
pub const STORE: u8 = 0x11; /// - 0: opcode
/// - 1: register
/// - 2..5: operand
pub const MOV_INT: u8 = 0x01;
pub const ALLOC: u8 = 0x20; pub const MOV_LONG: u8 = 0x02;
pub const DEALLOC: u8 = 0x21; pub const MOV_DOUBLE: u8 = 0x03;
pub const ALLOC_RAW: u8 = 0x22;
pub const DEALLOC_RAW: u8 = 0x23;
pub const PLATFORM_CALL: u8 = 0x30; /// ## mov(target_register: u8, source_register: u8)
pub const INVOKE_FN: u8 = 0x31; /// 0: opcode
pub const INVOKE_VIRTUAL: u8 = 0x32; /// 1: target_register
pub const INVOKE_DYNAMIC: u8 = 0x33; /// 2: source_register
pub const MOV_REGISTER: u8 = 0x04;
pub const ADD: u8 = 0x40; /// ## alloc(register: u8, size: u32)
pub const SUBTRACT: u8 = 0x41; /// 0: opcode
pub const MULTIPLY: u8 = 0x42; /// 1: register
pub const DIVIDE: u8 = 0x43; /// 2..5: size
pub const MODULO: u8 = 0x44; pub const ALLOC: u8 = 0x05;
pub const POWER: u8 = 0x45;
macro_rules! push_bytes { /// ## dealloc(register: u8)
( $dest: expr, $src: expr ) => { /// 0: opcode
for b in $src { /// 1: register
$dest.push(b); pub const DEALLOC: u8 = 0x06;
}
}; /// ## mov_int_to(register: u8, offset: u32, operand: u32)
} /// 0: opcode
/// 1: register
/// 2..5: offset
/// 6..9: operand
pub const MOV_INT_TO: u8 = 0x07;
pub const MOV_LONG_TO: u8 = 0x08;
pub const MOV_DOUBLE_TO: u8 = 0x09;
pub const MOV_REGISTER_TO: u8 = 0x0a;
pub const MOV_CONST: u8 = 0x0b;
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 MOV_SIZE_OF: u8 = 0x30;
pub const MULTIPLY: u8 = 0x40;
pub const LOAD_OBJECT: u8 = 0x50;
pub const STORE: u8 = 0x60;
macro_rules! push_number { macro_rules! push_number {
( $dest: expr, $num: expr ) => { ( $dest: expr, $num: expr ) => {
@ -59,9 +79,10 @@ pub fn add_mov_register(code: &mut Vec<u8>, target_register: u8, source_register
code.push(source_register); code.push(source_register);
} }
pub fn add_alloc(code: &mut Vec<u8>, target_register: u8, implementation_name: &str) { pub fn add_alloc(code: &mut Vec<u8>, target_register: u8, size: u32, implementation_name: &str) {
code.push(ALLOC); code.push(ALLOC);
code.push(target_register); code.push(target_register);
push_number!(code, size);
push_number!(code, implementation_name.len() as u32); push_number!(code, implementation_name.len() as u32);
push_string!(code, implementation_name); push_string!(code, implementation_name);
} }
@ -77,17 +98,46 @@ pub fn add_dealloc(code: &mut Vec<u8>, register: u8) {
code.push(register); code.push(register);
} }
pub fn add_load(code: &mut Vec<u8>, target_register: u8, source_register: u8, field_index: usize) { pub fn add_mov_int_to(code: &mut Vec<u8>, register: u8, offset: u32, operand: u32) {
code.push(LOAD); code.push(MOV_INT_TO);
code.push(target_register); code.push(register);
code.push(source_register); push_number!(code, offset);
push_number!(code, field_index); push_number!(code, operand);
} }
pub fn add_store(code: &mut Vec<u8>, target_register: u8, field_index: usize, source_register: u8) { pub fn add_mov_register_to(
code: &mut Vec<u8>,
target_register: u8,
offset: u32,
source_register: u8,
) {
code.push(MOV_REGISTER_TO);
code.push(target_register);
push_number!(code, offset);
code.push(source_register);
}
pub fn add_load_object(
code: &mut Vec<u8>,
target_register: u8,
source_register: u8,
offset: usize
) {
code.push(LOAD_OBJECT);
code.push(target_register);
code.push(source_register);
push_number!(code, offset);
}
pub fn add_store(
code: &mut Vec<u8>,
target_register: u8,
offset: usize,
source_register: u8,
) {
code.push(STORE); code.push(STORE);
code.push(target_register); code.push(target_register);
push_number!(code, field_index); push_number!(code, offset);
code.push(source_register); code.push(source_register);
} }
@ -133,6 +183,12 @@ pub fn add_invoke_fn(code: &mut Vec<u8>, fn_name: &str, return_register: u8, arg
} }
} }
pub fn add_mov_size_of(code: &mut Vec<u8>, target_register: u8, source_register: u8) {
code.push(MOV_SIZE_OF);
code.push(target_register);
code.push(source_register);
}
pub fn add_multiply( pub fn add_multiply(
code: &mut Vec<u8>, code: &mut Vec<u8>,
target_register: u8, target_register: u8,

View File

@ -1,6 +1,6 @@
use crate::vm::dvm_value::DvmValue; use crate::vm::dvm_value::DvmValue;
use crate::vm::mem::read_field_by_name; use crate::vm::mem::get_field_value;
use crate::vm::object::DvmObject; use crate::vm::object::DmAllocObject;
use crate::vm::{DvmContext, DvmState}; use crate::vm::{DvmContext, DvmState};
use std::rc::Rc; use std::rc::Rc;
@ -8,7 +8,9 @@ pub fn dm_print(args: Vec<DvmValue>, _state: &mut DvmState, _context: &DvmContex
if args.len() != 1 { if args.len() != 1 {
return DvmValue::Void; // TODO: make exception return DvmValue::Void; // TODO: make exception
} }
print!("{}", get_string(&args[0])); unsafe {
print!("{}", get_string(&args[0]));
}
DvmValue::Void DvmValue::Void
} }
@ -16,11 +18,13 @@ pub fn dm_println(args: Vec<DvmValue>, _state: &mut DvmState, _context: &DvmCont
if args.len() != 1 { if args.len() != 1 {
return DvmValue::Uninit; return DvmValue::Uninit;
} }
println!("{}", get_string(&args[0])); unsafe {
println!("{}", get_string(&args[0]));
}
DvmValue::Void DvmValue::Void
} }
fn get_string(dvm_value: &DvmValue) -> String { unsafe fn get_string(dvm_value: &DvmValue) -> String {
match dvm_value { match dvm_value {
DvmValue::Byte(b) => b.to_string(), DvmValue::Byte(b) => b.to_string(),
DvmValue::Int(i) => i.to_string(), DvmValue::Int(i) => i.to_string(),
@ -34,22 +38,35 @@ fn get_string(dvm_value: &DvmValue) -> String {
} }
} }
fn object_to_string(alloc_object_rc: Rc<DvmObject>) -> String { fn object_to_string(alloc_object_rc: Rc<DmAllocObject>) -> String {
if alloc_object_rc.implementation().fqn == "std::core::StringImpl" { if alloc_object_rc.implementation.fqn == "std::core::StringImpl" {
extract_string_from_string(alloc_object_rc.clone()) extract_string_from_string(alloc_object_rc.clone())
} else { } else {
todo!("what happens if we don't have a String?") todo!("what happens if we don't have a String?")
} }
} }
fn extract_string_from_string(string_object: Rc<DvmObject>) -> String { fn extract_string_from_string(string_object: Rc<DmAllocObject>) -> String {
let bytes_object = read_field_by_name("bytes", &string_object).expect_object(); let bytes_field = string_object
if bytes_object.implementation().fqn != "std::core::ArrayImpl" { .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_object();
if bytes_object.implementation.fqn != "std::core::ArrayImpl" {
panic!("String.bytes field is not a std::core::ArrayImpl"); panic!("String.bytes field is not a std::core::ArrayImpl");
} }
let address = read_field_by_name("ptr_address", &bytes_object).expect_usize(); let ptr_address_field = bytes_object
let size = read_field_by_name("ptr_size", &bytes_object).expect_usize(); .implementation
.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 ptr_size_field = bytes_object
.implementation
.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 raw_bytes_pointer = address as *mut u8; let raw_bytes_pointer = address as *mut u8;
let mut v: Vec<u8> = Vec::new(); let mut v: Vec<u8> = Vec::new();

View File

@ -22,5 +22,15 @@ macro_rules! get_64_le {
}; };
} }
#[macro_export]
macro_rules! push_bytes {
( $dest: expr, $src: expr ) => {
for b in $src {
$dest.push(b);
}
};
}
pub use get_32_le; pub use get_32_le;
pub use get_64_le; pub use get_64_le;
pub use push_bytes;