diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 35cac1b..59f0199 100644 --- a/src/vm/mod.rs +++ b/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::() { + u += next_8!($byte_code, usize) << (8 * i); + } + u + }}; +} + macro_rules! read_array_u8 { ( $iter: expr ) => {{ 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(); 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::()) + }; + + 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 => { let target_register = next_8!(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)] mod run_code_tests { + use crate::vm::dm_type::DmType; + use crate::vm::object_type::{DmField, DmImplementation}; use super::*; macro_rules! assert_register { @@ -530,6 +606,13 @@ mod run_code_tests { fn setup() -> (DvmState, DvmContext) { (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] fn mov_1_as_int() { @@ -568,4 +651,29 @@ mod run_code_tests { run_byte_code(&mut state, &context, &code); 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); + } } diff --git a/src/vm/op_codes.rs b/src/vm/op_codes.rs index 93ab3ce..d5d5508 100644 --- a/src/vm/op_codes.rs +++ b/src/vm/op_codes.rs @@ -51,6 +51,10 @@ 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 { ( $dest: expr, $num: expr ) => { push_bytes!($dest, $num.to_le_bytes()) @@ -113,6 +117,30 @@ pub fn add_mov_register_to( code.push(source_register); } +pub fn add_load_object( + code: &mut Vec, + 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, + 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( code: &mut Vec, address_register: u8,