Compare commits
5 Commits
652c1dd7f2
...
cf0c44e627
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cf0c44e627 | ||
![]() |
7aa93c3986 | ||
![]() |
9c4ca23765 | ||
![]() |
420db38f70 | ||
![]() |
376ac2fa3a |
@ -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]
|
||||||
|
@ -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));
|
||||||
|
@ -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?")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
130
src/vm/mem.rs
130
src/vm/mem.rs
@ -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)
|
|
||||||
}
|
}
|
||||||
|
195
src/vm/mod.rs
195
src/vm/mod.rs
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
|
||||||
|
Loading…
Reference in New Issue
Block a user