Add basic, but failing, implementation of load/store object.
This commit is contained in:
parent
574f7ea7a1
commit
652c1dd7f2
108
src/vm/mod.rs
108
src/vm/mod.rs
@ -213,6 +213,16 @@ macro_rules! next_64_le {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! next_usize_le {
|
||||||
|
( $byte_code: expr ) => {{
|
||||||
|
let mut u: usize = 0;
|
||||||
|
for i in 0..std::mem::size_of::<usize>() {
|
||||||
|
u += next_8!($byte_code, usize) << (8 * i);
|
||||||
|
}
|
||||||
|
u
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! read_array_u8 {
|
macro_rules! read_array_u8 {
|
||||||
( $iter: expr ) => {{
|
( $iter: expr ) => {{
|
||||||
let arr_length = next_8!($iter, u8);
|
let arr_length = next_8!($iter, u8);
|
||||||
@ -284,6 +294,70 @@ 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 => {
|
||||||
|
let target_register = next_8!(iter, usize);
|
||||||
|
let source_register = next_8!(iter, usize);
|
||||||
|
let offset = next_usize_le!(iter);
|
||||||
|
|
||||||
|
let source_object = state.registers
|
||||||
|
.get(source_register)
|
||||||
|
.unwrap()
|
||||||
|
.expect_object();
|
||||||
|
|
||||||
|
let object = unsafe {
|
||||||
|
Rc::from_raw(source_object.data.add(offset).cast::<DmAllocObject>())
|
||||||
|
};
|
||||||
|
|
||||||
|
state.registers[target_register] = DvmValue::Object(object);
|
||||||
|
}
|
||||||
|
STORE => {
|
||||||
|
let target_register = next_8!(iter, usize);
|
||||||
|
let offset = next_usize_le!(iter);
|
||||||
|
let source_register = next_8!(iter, usize);
|
||||||
|
|
||||||
|
let target_alloc_object = state
|
||||||
|
.registers
|
||||||
|
.get(target_register)
|
||||||
|
.unwrap()
|
||||||
|
.expect_object();
|
||||||
|
|
||||||
|
let source_value = std::mem::replace(&mut state.registers[source_register], DvmValue::Uninit);
|
||||||
|
|
||||||
|
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 alloc_size = next_32_le!(iter, usize);
|
||||||
@ -516,6 +590,8 @@ 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 crate::vm::dm_type::DmType;
|
||||||
|
use crate::vm::object_type::{DmField, DmImplementation};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
macro_rules! assert_register {
|
macro_rules! assert_register {
|
||||||
@ -530,6 +606,13 @@ mod run_code_tests {
|
|||||||
fn setup() -> (DvmState, DvmContext) {
|
fn setup() -> (DvmState, DvmContext) {
|
||||||
(DvmState::new(), DvmContext::new())
|
(DvmState::new(), DvmContext::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn impl_with_object_field() -> DmImplementation {
|
||||||
|
let mut dm_impl = DmImplementation::new("ImplWithObjectField", "ImplWithObjectField", None);
|
||||||
|
let object_field = DmField::new("object_field", DmType::Object, 0);
|
||||||
|
dm_impl.fields.push(object_field);
|
||||||
|
dm_impl
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mov_1_as_int() {
|
fn mov_1_as_int() {
|
||||||
@ -568,4 +651,29 @@ mod run_code_tests {
|
|||||||
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]
|
||||||
|
fn load_object() {
|
||||||
|
let dummy_impl = impl_with_object_field();
|
||||||
|
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");
|
||||||
|
dummy_lib.implementations.push(dummy_impl_rc.clone());
|
||||||
|
|
||||||
|
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, 1, dummy_impl_rc.size_in_bytes() as u32, &dummy_impl_rc.fqn);
|
||||||
|
add_store(&mut code, 0, dummy_impl_object_field.data_offset(), 1);
|
||||||
|
add_load_object(&mut code, 2, 0, dummy_impl_object_field.data_offset());
|
||||||
|
|
||||||
|
let (mut state, mut context) = setup();
|
||||||
|
state.registers.resize(3, DvmValue::Uninit);
|
||||||
|
context.load_libs(vec![Rc::new(dummy_lib)]);
|
||||||
|
run_byte_code(&mut state, &context, &code);
|
||||||
|
|
||||||
|
let referenced_object = state.registers.get(1).unwrap().expect_object();
|
||||||
|
assert_register!(DvmValue::Object(referenced_object), state, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,10 @@ pub const MOV_SIZE_OF: u8 = 0x30;
|
|||||||
|
|
||||||
pub const MULTIPLY: u8 = 0x40;
|
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 ) => {
|
||||||
push_bytes!($dest, $num.to_le_bytes())
|
push_bytes!($dest, $num.to_le_bytes())
|
||||||
@ -113,6 +117,30 @@ pub fn add_mov_register_to(
|
|||||||
code.push(source_register);
|
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(target_register);
|
||||||
|
push_number!(code, offset);
|
||||||
|
code.push(source_register);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_mov_const(
|
pub fn add_mov_const(
|
||||||
code: &mut Vec<u8>,
|
code: &mut Vec<u8>,
|
||||||
address_register: u8,
|
address_register: u8,
|
||||||
|
Loading…
Reference in New Issue
Block a user