Compare commits

...

5 Commits

Author SHA1 Message Date
Jesse Brault
cf0c44e627 Update of semantics of Move Register operation. 2024-12-28 16:42:43 -06:00
Jesse Brault
7aa93c3986 Clean up op codes. 2024-12-28 15:35:35 -06:00
Jesse Brault
9c4ca23765 Remove deprecated op codes. 2024-12-28 15:14:24 -06:00
Jesse Brault
420db38f70 Properly implement load and store instructions. 2024-12-28 15:10:56 -06:00
Jesse Brault
376ac2fa3a Rename DmAllocObject to DvmObject. 2024-12-28 10:23:05 -06:00
11 changed files with 247 additions and 462 deletions

View File

@ -91,7 +91,7 @@ The operand is converted to a `bool` at runtime by the virtual machine.
=== Move Register === Move Register
Copies the value in one register to another. Moves or copies (see below) the value in one register to another.
[source] [source]
---- ----
@ -101,60 +101,12 @@ mov_register(
) )
---- ----
=== Load Byte For `Byte`, `Int`, `Long`, `USize`, `Double`, and `Boolean`, the value is **copied** to the register. For `Object`
values, the value is **moved**, meaning that register takes ownership of the referenced object.
Loads the target register with the `u8` stored at the offset from the base of the object stored in the source register. === Load
[source] Loads the target register with the `DvmValue` inner value stored in the field at `field_index` in the object in the
----
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]
@ -162,16 +114,15 @@ source register.
load_object( load_object(
target_register: u8, target_register: u8,
source_register: u8, source_register: u8,
offset: usize field_index: usize
) )
---- ----
The source register must contain a `DvmValue::Object` at runtime, and the data at the offset from that object's base The source register must contain a `DvmValue::Object` at runtime.
must be a valid `Rc<DvmObject>`.
=== Store === Store
Stores the value contained in the source register to the offset from the base of the object contained in the target Stores the value contained in the source register to the field at `field_index` in 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_invoke_fn, add_mov_const, add_mov_register_to, add_platform_call, 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::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, 0); let array_impl_ptr_address_fld = DmField::new("ptr_address", DmType::USize);
let array_impl_ptr_size_fld = DmField::new("ptr_size", DmType::USize, 8); let array_impl_ptr_size_fld = DmField::new("ptr_size", DmType::USize);
let array_impl_length_fld = DmField::new("length", DmType::Long, 16); let array_impl_length_fld = DmField::new("length", DmType::Long);
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_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 0, 1); add_store(&mut array_impl_ctor_0_bytecode, 0, 0, 1);
add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 8, 2); add_store(&mut array_impl_ctor_0_bytecode, 0, 1, 2);
add_mov_register_to(&mut array_impl_ctor_0_bytecode, 0, 16, 3); add_store(&mut array_impl_ctor_0_bytecode, 0, 2, 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, 0); let bytes_field = DmField::new("bytes", DmType::Object);
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_mov_register_to(&mut string_ctor_0_bytecode, 0, 0, 1); add_store(&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,7 +91,6 @@ 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));
@ -110,12 +109,7 @@ 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( add_alloc(&mut main_byte_code, 2, "std::core::ArrayImpl");
&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(
@ -126,12 +120,7 @@ fn main() {
); );
// Alloc StringImpl greeting // Alloc StringImpl greeting
add_alloc( add_alloc(&mut main_byte_code, 4, "std::core::StringImpl");
&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(
@ -144,6 +133,12 @@ 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,7 +7,6 @@ pub enum DmType {
Boolean, Boolean,
Object, Object,
USize, USize,
Unit,
} }
impl DmType { impl DmType {
@ -20,7 +19,6 @@ 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::DmAllocObject; use crate::vm::object::DvmObject;
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<DmAllocObject>), Object(Rc<DvmObject>),
USize(usize), USize(usize),
Uninit, Uninit,
Void, Void,
@ -23,7 +23,7 @@ impl DvmValue {
} }
} }
pub fn expect_object(&self) -> Rc<DmAllocObject> { pub fn expect_object(&self) -> Rc<DvmObject> {
if let DvmValue::Object(o) = self { if let DvmValue::Object(o) = self {
o.clone() o.clone()
} else { } else {
@ -31,6 +31,13 @@ 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,70 +1,86 @@
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::DmAllocObject; use crate::vm::object::DvmObject;
use crate::vm::object_type::DmField;
use std::rc::Rc; use std::rc::Rc;
pub unsafe fn get_field_value(dm_field: &DmField, self_object: &DmAllocObject) -> DvmValue { unsafe fn read_field(data_pointer: *const u8, dm_type: &DmType) -> DvmValue {
let data_size = dm_field.dm_type().size_in_bytes(); match dm_type {
let mut raw_data: Vec<u8> = Vec::with_capacity(data_size); DmType::Byte => DvmValue::Byte(data_pointer.read()),
for i in dm_field.data_offset()..(dm_field.data_offset() + data_size) { DmType::Int => DvmValue::Int(data_pointer.cast::<i32>().read()),
raw_data.push(self_object.data.offset(i as isize).read()); DmType::Long => DvmValue::Long(data_pointer.cast::<i64>().read()),
} DmType::USize => DvmValue::USize(data_pointer.cast::<usize>().read()),
match dm_field.dm_type() { DmType::Double => DvmValue::Double(data_pointer.cast::<f64>().read()),
DmType::Byte => DvmValue::Byte(raw_data[0]), DmType::Boolean => DvmValue::Boolean(data_pointer.cast::<bool>().read()),
DmType::Int => DvmValue::Int(i32::from_ne_bytes( DmType::Object => DvmValue::Object(data_pointer.cast::<Rc<DvmObject>>().read()),
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,
} }
} }
macro_rules! read_array { pub fn read_field_by_name(field_name: &str, self_object: &DvmObject) -> DvmValue {
( $T: ty, $raw_data: expr, $length: expr ) => {{ let (field_index, field) = self_object
let t_size = size_of::<$T>(); .implementation()
let mut arr: Vec<$T> = Vec::with_capacity($length); .fields
for i in 0..$length { .iter()
arr.push(<$T>::from_ne_bytes( .enumerate()
$raw_data[(i * t_size)..(i * t_size + t_size)] .find(|(_index, field)| field.name() == field_name)
.try_into() .expect(&format!(
.unwrap(), "Cannot find field {} in {}",
)) field_name,
self_object.implementation().fqn
));
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 {
let field = &self_object.implementation().fields[index];
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) {
match value {
DvmValue::Byte(b) => {
data_pointer.write(b);
} }
arr 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."),
}
} }
fn read_i32_array(raw_data: &Vec<u8>, length: usize) -> Vec<i32> { pub fn write_field_by_name(field_name: &str, self_object: &DvmObject, value: DvmValue) {
read_array!(i32, raw_data, length) let field_index = self_object
.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) };
} }
fn read_i64_array(raw_data: &Vec<u8>, length: usize) -> Vec<i64> { pub fn write_field_by_index(index: usize, self_object: &DvmObject, value: DvmValue) {
read_array!(i64, raw_data, length) let data_pointer = self_object.data()[index];
} unsafe { write_field(data_pointer, value) };
fn read_f64_array(raw_data: &Vec<u8>, length: usize) -> Vec<f64> {
read_array!(f64, raw_data, length)
}
fn read_bool_array(raw_data: &Vec<u8>) -> Vec<bool> {
raw_data.iter().map(|b| *b == 1).collect()
}
fn read_usize_array(raw_data: &Vec<u8>, length: usize) -> Vec<usize> {
read_array!(usize, raw_data, length)
} }

View File

@ -11,7 +11,8 @@ 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::object::DmAllocObject; use crate::vm::mem::{read_field_by_index, write_field_by_index};
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};
@ -273,6 +274,9 @@ 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;
@ -294,73 +298,37 @@ 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_OBJECT => { LOAD => {
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 offset = next_usize_le!(iter); let source_object_field_index = next_usize_le!(iter);
let source_object = state.registers let source_object = state
.registers
.get(source_register) .get(source_register)
.unwrap() .unwrap()
.expect_object(); .expect_object();
let object = unsafe { state.registers[target_register] =
Rc::from_raw(source_object.data.add(offset).cast::<DmAllocObject>()) read_field_by_index(source_object_field_index, &source_object);
};
state.registers[target_register] = DvmValue::Object(object);
} }
STORE => { STORE => {
let target_register = next_8!(iter, usize); let target_register = next_8!(iter, usize);
let offset = next_usize_le!(iter); let target_object_field_index = next_usize_le!(iter);
let source_register = next_8!(iter, usize); let source_register = next_8!(iter, usize);
let target_alloc_object = state let target_object = state
.registers .registers
.get(target_register) .get(target_register)
.unwrap() .unwrap()
.expect_object(); .expect_object();
let source_value = std::mem::replace(&mut state.registers[source_register], DvmValue::Uninit); let source_value =
std::mem::replace(&mut state.registers[source_register], DvmValue::Uninit);
match source_value { write_field_by_index(target_object_field_index, &target_object, 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
@ -373,86 +341,19 @@ 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 = DmAllocObject::new(alloc_size, implementation.clone()); let dm_alloc_object = DvmObject::new(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 dm_alloc_object = state let dvm_object = state
.registers .registers
.get(target_register) .get(target_register)
.unwrap() .unwrap()
.expect_object(); .expect_object();
drop(dm_alloc_object); // explicit drop(dvm_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);
@ -564,7 +465,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();
@ -575,9 +476,6 @@ 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!()
} }
@ -590,9 +488,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 ) => {
@ -603,13 +501,17 @@ mod run_code_tests {
}; };
} }
fn setup() -> (DvmState, DvmContext) { fn setup(number_of_registers: usize) -> (DvmState, DvmContext) {
(DvmState::new(), DvmContext::new()) let mut state = DvmState::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, 0); let object_field = DmField::new("object_field", DmType::Object);
dm_impl.fields.push(object_field); dm_impl.fields.push(object_field);
dm_impl dm_impl
} }
@ -618,7 +520,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(); let (mut state, context) = setup(1);
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);
} }
@ -627,7 +529,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(); let (mut state, context) = setup(1);
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);
} }
@ -636,7 +538,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(); let (mut state, context) = setup(1);
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);
} }
@ -646,34 +548,29 @@ 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(); let (mut state, context) = setup(2);
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);
} }
#[test] #[test]
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.size_in_bytes() as u32, &dummy_impl_rc.fqn); add_alloc(&mut code, 0, &dummy_impl_rc.fqn);
add_alloc(&mut code, 1, dummy_impl_rc.size_in_bytes() as u32, &dummy_impl_rc.fqn); add_alloc(&mut code, 1, &dummy_impl_rc.fqn);
add_store(&mut code, 0, dummy_impl_object_field.data_offset(), 1); add_store(&mut code, 0, 0, 1);
add_load_object(&mut code, 2, 0, dummy_impl_object_field.data_offset()); add_load(&mut code, 2, 0, 0);
let (mut state, mut context) = setup(); let (mut state, mut context) = setup(3);
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);
let referenced_object = state.registers.get(1).unwrap().expect_object(); assert!(state.registers[2].is_object())
assert_register!(DvmValue::Object(referenced_object), state, 2);
} }
} }

View File

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

View File

@ -1,5 +1,5 @@
use crate::vm::dm_type::DmType; use crate::vm::dm_type::DmType;
use crate::vm::object::DmAllocObject; use crate::vm::object::DvmObject;
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: &DmAllocObject) -> Option<Rc<DmMethod>> { pub fn get_method(&self, name: &str, self_object: &DvmObject) -> 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: &DmAllocObject) -> Option<&DmProperty> { pub fn get_property(&self, name: &str, self_object: &DvmObject) -> 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: &DmAllocObject) -> Option<Rc<DmMethod>> { pub fn get_method(&self, name: &str, self_object: &DvmObject) -> 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,17 +209,13 @@ impl DmImplementation {
None None
} }
pub fn get_property(&self, name: &str, self_object: &DmAllocObject) -> Option<Rc<DmProperty>> { pub fn get_property(&self, name: &str, self_object: &DvmObject) -> Option<Rc<DmProperty>> {
todo!() todo!()
} }
pub fn get_field(&self, name: &str, self_object: &DmAllocObject) -> Option<&DmField> { pub fn get_field(&self, name: &str, self_object: &DvmObject) -> 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)]
@ -239,7 +235,6 @@ 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 {
@ -249,11 +244,10 @@ impl PartialEq for DmField {
} }
impl DmField { impl DmField {
pub fn new(name: &str, dm_type: DmType, data_offset: usize) -> Self { pub fn new(name: &str, dm_type: DmType) -> Self {
DmField { DmField {
name: name.to_string(), name: name.to_string(),
dm_type, dm_type,
data_offset,
} }
} }
@ -264,12 +258,4 @@ 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,59 +1,39 @@
use crate::push_bytes; pub const MOV_BYTE: u8 = 0x01;
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;
/// ## mov(register: u8, operand: u32) pub const LOAD: u8 = 0x10;
/// - 0: opcode pub const STORE: u8 = 0x11;
/// - 1: register
/// - 2..5: operand
pub const MOV_INT: u8 = 0x01;
pub const MOV_LONG: u8 = 0x02; pub const ALLOC: u8 = 0x20;
pub const MOV_DOUBLE: u8 = 0x03; pub const DEALLOC: u8 = 0x21;
pub const ALLOC_RAW: u8 = 0x22;
pub const DEALLOC_RAW: u8 = 0x23;
/// ## mov(target_register: u8, source_register: u8) pub const PLATFORM_CALL: u8 = 0x30;
/// 0: opcode pub const INVOKE_FN: u8 = 0x31;
/// 1: target_register pub const INVOKE_VIRTUAL: u8 = 0x32;
/// 2: source_register pub const INVOKE_DYNAMIC: u8 = 0x33;
pub const MOV_REGISTER: u8 = 0x04;
/// ## alloc(register: u8, size: u32) pub const ADD: u8 = 0x40;
/// 0: opcode pub const SUBTRACT: u8 = 0x41;
/// 1: register pub const MULTIPLY: u8 = 0x42;
/// 2..5: size pub const DIVIDE: u8 = 0x43;
pub const ALLOC: u8 = 0x05; pub const MODULO: u8 = 0x44;
pub const POWER: u8 = 0x45;
/// ## dealloc(register: u8) macro_rules! push_bytes {
/// 0: opcode ( $dest: expr, $src: expr ) => {
/// 1: register for b in $src {
pub const DEALLOC: u8 = 0x06; $dest.push(b);
}
/// ## 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 ) => {
@ -79,10 +59,9 @@ 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, size: u32, implementation_name: &str) { pub fn add_alloc(code: &mut Vec<u8>, target_register: u8, 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);
} }
@ -98,46 +77,17 @@ pub fn add_dealloc(code: &mut Vec<u8>, register: u8) {
code.push(register); code.push(register);
} }
pub fn add_mov_int_to(code: &mut Vec<u8>, register: u8, offset: u32, operand: u32) { pub fn add_load(code: &mut Vec<u8>, target_register: u8, source_register: u8, field_index: usize) {
code.push(MOV_INT_TO); code.push(LOAD);
code.push(register);
push_number!(code, offset);
push_number!(code, operand);
}
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(target_register);
code.push(source_register); code.push(source_register);
push_number!(code, offset); push_number!(code, field_index);
} }
pub fn add_store( pub fn add_store(code: &mut Vec<u8>, target_register: u8, field_index: usize, source_register: u8) {
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, offset); push_number!(code, field_index);
code.push(source_register); code.push(source_register);
} }
@ -183,12 +133,6 @@ 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::get_field_value; use crate::vm::mem::read_field_by_name;
use crate::vm::object::DmAllocObject; use crate::vm::object::DvmObject;
use crate::vm::{DvmContext, DvmState}; use crate::vm::{DvmContext, DvmState};
use std::rc::Rc; use std::rc::Rc;
@ -8,9 +8,7 @@ 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
} }
unsafe { print!("{}", get_string(&args[0]));
print!("{}", get_string(&args[0]));
}
DvmValue::Void DvmValue::Void
} }
@ -18,13 +16,11 @@ 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;
} }
unsafe { println!("{}", get_string(&args[0]));
println!("{}", get_string(&args[0]));
}
DvmValue::Void DvmValue::Void
} }
unsafe fn get_string(dvm_value: &DvmValue) -> String { 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(),
@ -38,35 +34,22 @@ unsafe fn get_string(dvm_value: &DvmValue) -> String {
} }
} }
fn object_to_string(alloc_object_rc: Rc<DmAllocObject>) -> String { fn object_to_string(alloc_object_rc: Rc<DvmObject>) -> 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<DmAllocObject>) -> String { fn extract_string_from_string(string_object: Rc<DvmObject>) -> String {
let bytes_field = string_object let bytes_object = read_field_by_name("bytes", &string_object).expect_object();
.implementation if bytes_object.implementation().fqn != "std::core::ArrayImpl" {
.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 ptr_address_field = bytes_object let address = read_field_by_name("ptr_address", &bytes_object).expect_usize();
.implementation let size = read_field_by_name("ptr_size", &bytes_object).expect_usize();
.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,15 +22,5 @@ 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;