From e4ee8fd2db29157f4a7d88611c968da74e34ed59 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Thu, 28 Nov 2024 08:01:50 -0600 Subject: [PATCH] Implement basic alloc and dealloc functionality. --- src/lexer/mod.rs | 1 + src/vm/mod.rs | 75 +++++++++++++++++++++++++++++++++++----------- src/vm/op_codes.rs | 30 ++++++++++++------- 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index d4897c3..3c32844 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -141,6 +141,7 @@ mod tests { } #[test] + #[cfg_attr(miri, ignore)] fn simple_ns_file() { let mut src_file = File::open(Path::new("test-data/lexer/simple_ns.dm")).unwrap(); let mut src = String::new(); diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 62df4de..5f786a3 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,7 +1,13 @@ mod op_codes; use op_codes::*; -use std::alloc::{alloc_zeroed, Layout}; +use std::alloc::{alloc_zeroed, dealloc, Layout}; + +struct DmObject { + pointer: *mut u8, + size: usize, + layout: Layout, +} pub fn run(code: &Vec, registers: &mut Vec, register_types: &mut Vec) { let mut i = 0; @@ -41,29 +47,50 @@ pub fn run(code: &Vec, registers: &mut Vec, register_types: &mut Vec { let target_register = code[i + 1] as usize; - let n_bytes_to_allocate = code[i + 2] as u32 - + ((code[i + 3] as u32) << 8) - + ((code[i + 4] as u32) << 16) - + ((code[i + 5] as u32) << 24); - let layout = Layout::from_size_align(n_bytes_to_allocate as usize, 4).unwrap(); - let allocated = unsafe { alloc_zeroed(layout) }; - registers[target_register] = allocated as u64; + let size = code[i + 2] as usize + + ((code[i + 3] as usize) << 8) + + ((code[i + 4] as usize) << 16) + + ((code[i + 5] as usize) << 24); + let layout = Layout::from_size_align(size, 4).unwrap(); + let pointer = unsafe { alloc_zeroed(layout) }; + let dm_object = Box::new(DmObject { + pointer, + size, + layout, + }); + let dm_object_pointer = Box::into_raw(dm_object) as u64; + registers[target_register] = dm_object_pointer; register_types[target_register] = RegisterType::Pointer; i += 6; } + DEALLOC => { + let target_register = code[i + 1] as usize; + let box_address = registers[target_register]; + unsafe { + let dm_object = Box::from_raw(box_address as *mut DmObject); + dealloc(dm_object.pointer, dm_object.layout); + } + registers[target_register] = 0; + register_types[target_register] = RegisterType::Int; + i += 2; + } MOV_INT_TO => { let target_register = code[i + 1] as usize; if register_types[target_register] != RegisterType::Pointer { panic!("target_register {} is not a Pointer", target_register); } let offset = convert_to_u32(&code[(i + 2)..(i + 6)]) as isize; - let target = registers[target_register] as *mut u8; - unsafe { - target.offset(offset).write(code[i + 6]); - target.offset(offset + 1).write(code[i + 7]); - target.offset(offset + 2).write(code[i + 8]); - target.offset(offset + 3).write(code[i + 9]); - } + let box_address = registers[target_register]; + let new_address = unsafe { + let dm_object = Box::from_raw(box_address as *mut DmObject); + let pointer = dm_object.pointer; + pointer.offset(offset).write(code[i + 6]); + pointer.offset(offset + 1).write(code[i + 7]); + pointer.offset(offset + 2).write(code[i + 8]); + pointer.offset(offset + 3).write(code[i + 9]); + Box::into_raw(dm_object) as u64 + }; + registers[target_register] = new_address; i += 10; } _ => panic!("Invalid code instruction"), @@ -78,6 +105,7 @@ fn convert_to_u32(bytes: &[u8]) -> u32 { #[cfg(test)] mod tests { use super::*; + use std::alloc::dealloc; fn init_registers(n_registers: usize) -> (Vec, Vec) { (vec![0; n_registers], vec![RegisterType::Int; n_registers]) @@ -128,9 +156,22 @@ mod tests { let mut registers = vec![0; 16]; let mut register_types = vec![RegisterType::Int; 16]; run(&code, &mut registers, &mut register_types); - let target = registers[0] as *mut u8; + let box_address = registers[0]; unsafe { - assert_eq!(0xff, *target); + let dm_object = Box::from_raw(box_address as *mut DmObject); + assert_eq!(0xff, *dm_object.pointer); + dealloc(dm_object.pointer, dm_object.layout); } } + + #[test] + fn alloc_and_dealloc_expect_register_cleared() { + let mut code = Vec::new(); + add_alloc(&mut code, 0, 4); + add_dealloc(&mut code, 0); + let (mut registers, mut register_types) = init_registers(1); + run(&code, &mut registers, &mut register_types); + assert_eq!(0, registers[0]); + assert_eq!(RegisterType::Int, register_types[0]); + } } diff --git a/src/vm/op_codes.rs b/src/vm/op_codes.rs index 3a04f29..9e202ef 100644 --- a/src/vm/op_codes.rs +++ b/src/vm/op_codes.rs @@ -2,35 +2,40 @@ /// - 0: opcode /// - 1: register /// - 2..5: operand -pub const MOV_INT: u8 = 0x00; +pub const MOV_INT: u8 = 0x01; -pub const MOV_LONG: u8 = 0x01; -pub const MOV_DOUBLE: u8 = 0x02; +pub const MOV_LONG: u8 = 0x02; +pub const MOV_DOUBLE: u8 = 0x03; /// ## mov(target_register: u8, source_register: u8) /// 0: opcode /// 1: target_register /// 2: source_register -pub const MOV_REGISTER: u8 = 0x03; +pub const MOV_REGISTER: u8 = 0x04; /// ## alloc(register: u8, size: u32) /// 0: opcode /// 1: register /// 2..5: size -pub const ALLOC: u8 = 0x04; +pub const ALLOC: u8 = 0x05; + +/// ## dealloc(register: u8) +/// 0: opcode +/// 1: register +pub const DEALLOC: u8 = 0x06; /// ## mov_int_to(register: u8, offset: u32, operand: u32) /// 0: opcode /// 1: register /// 2..5: offset /// 6..9: operand -pub const MOV_INT_TO: u8 = 0x05; +pub const MOV_INT_TO: u8 = 0x07; -pub const MOV_LONG_TO: u8 = 0x06; -pub const MOV_DOUBLE_TO: u8 = 0x07; -pub const MOV_REGISTER_TO: u8 = 0x08; +pub const MOV_LONG_TO: u8 = 0x08; +pub const MOV_DOUBLE_TO: u8 = 0x09; +pub const MOV_REGISTER_TO: u8 = 0x0a; -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum RegisterType { Int, Long, @@ -60,6 +65,11 @@ pub fn add_alloc(code: &mut Vec, register: u8, size: u32) { } } +pub fn add_dealloc(code: &mut Vec, register: u8) { + code.push(DEALLOC); + code.push(register); +} + pub fn add_mov_int_to(code: &mut Vec, register: u8, offset: u32, operand: u32) { code.push(MOV_INT_TO); code.push(register);