From ae8f89bb4ef29bdc46876e2552777712c82be57f Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Tue, 15 Apr 2025 14:31:28 -0500 Subject: [PATCH] Update calling conventions. --- src/bin/dvm/main.rs | 98 ++++++++++++++++++++++++------ src/vm/instruction.rs | 20 ++++-- src/vm/mod.rs | 138 ++++++++++++++++++++++++++++++++---------- 3 files changed, 201 insertions(+), 55 deletions(-) diff --git a/src/bin/dvm/main.rs b/src/bin/dvm/main.rs index a65fabb..7fe620b 100644 --- a/src/bin/dvm/main.rs +++ b/src/bin/dvm/main.rs @@ -1,7 +1,7 @@ use deimos::object_file::{DvmObjectFile, DvmPath}; use deimos::vm::constant::DvmConstant; use deimos::vm::function::DvmFunction; -use deimos::vm::instruction::{Immediate, Instruction, Location}; +use deimos::vm::instruction::{Immediate, Instruction}; use deimos::vm::platform::get_std_lib_platform_functions; use deimos::vm::source_code_location::SourceCodeLocation; use deimos::vm::{dump_state, run_main_function, DvmContext, DvmState}; @@ -16,16 +16,23 @@ fn main() { // // fn main() { // println "Hello, World!" + // println foo() // } + // + // fn foo() = 42 let mut greeter_object_file = DvmObjectFile::new(DvmPath::new("greeter", "greeter.dmo")); - + + use Instruction::*; let main_instructions = vec![ - Instruction::MoveImmediate { - destination: Location::Register(0), + MoveImmediate { + destination_register: 0, immediate: Immediate::Constant(DvmConstant::String(String::from("Hello, World!"))), }, - Instruction::Push { source_register: 0 }, - Instruction::InvokeStaticPlatform { + // prepare for call to println + Push { source_register: 0 }, // save r0 + Push { source_register: 0 }, // arg0 + // call + InvokeStaticPlatform { function_name: Rc::new(String::from("std::core::println")), source_code_location: SourceCodeLocation { source_file_name: String::from("greeter.dm"), @@ -33,20 +40,55 @@ fn main() { char: 5, }, }, - Instruction::Pop { - // println return value + // unwind from call + Pop { destination_register: None, + }, // arg0 + Pop { + destination_register: Some(0), // restore r0 }, - Instruction::Pop { - // arg0 to println + // prepare for call to foo + Push { source_register: 0 }, // save r0 + InvokeStatic { + function_name: Rc::new(String::from("greeter::foo")), + source_code_location: SourceCodeLocation { + source_file_name: String::from("greeter.dm"), + line: 5, + char: 13, + }, + }, + Pop { destination_register: Some(0) }, // restore r0 + TakeReturnValue { + destination_register: 1, + }, + // call println again + Push { source_register: 1 }, // save r1 + Push { source_register: 0 }, // save r0 + Push { source_register: 1 }, // arg0 + InvokeStaticPlatform { + function_name: Rc::new(String::from("std::core::println")), + source_code_location: SourceCodeLocation { + source_file_name: String::from("greeter.dm"), + line: 5, + char: 5, + }, + }, + Pop { destination_register: None, + }, // arg0 + Pop { + destination_register: Some(0), // restore r0 }, - Instruction::MoveImmediate { - destination: Location::Register(1), + Pop { + destination_register: Some(1), // restore r1 + }, + // return 0 + MoveImmediate { + destination_register: 2, immediate: Immediate::Int(0), }, - Instruction::Push { source_register: 1 }, - Instruction::Return, + SetReturnValue { source_register: 2 }, + Return, // explicit, not needed ]; let main_function = DvmFunction::new( @@ -58,16 +100,34 @@ fn main() { char: 1, }, ); - + + let foo_function_instructions = vec![ + MoveImmediate { + destination_register: 0, + immediate: Immediate::Int(42), + }, + SetReturnValue { source_register: 0 }, + Return, // explicit, not needed + ]; + + let foo_function = DvmFunction::new( + "greeter::foo", + &foo_function_instructions, + SourceCodeLocation { + source_file_name: String::from("greeter.dm"), + line: 8, + char: 1, + }, + ); + greeter_object_file.add_function(main_function); + greeter_object_file.add_function(foo_function); let mut state = DvmState::new(); let mut context = DvmContext::new("greeter::main"); context.add_platform_functions(get_std_lib_platform_functions()); - greeter_object_file.load_to_context(&mut context, &|path| { - todo!() - }); - + greeter_object_file.load_to_context(&mut context, &|path| todo!()); + let exit_code = run_main_function(&mut state, &context); dump_state(&state, "After main!"); diff --git a/src/vm/instruction.rs b/src/vm/instruction.rs index 9aece0b..e105473 100644 --- a/src/vm/instruction.rs +++ b/src/vm/instruction.rs @@ -5,7 +5,7 @@ use std::rc::Rc; #[derive(Debug, Clone)] pub enum Instruction { MoveImmediate { - destination: Location, + destination_register: usize, immediate: Immediate, }, Copy { @@ -40,6 +40,12 @@ pub enum Instruction { function_name: Rc, source_code_location: SourceCodeLocation, }, + SetReturnValue { + source_register: usize, + }, + TakeReturnValue { + destination_register: usize, + }, Add { left: u8, right: u8, @@ -104,6 +110,9 @@ pub enum Instruction { offset: isize, }, Return, + DumpState { + message: String + } } #[derive(Debug, Clone)] @@ -121,8 +130,11 @@ pub enum Immediate { #[derive(Debug, Clone)] pub enum Location { Register(usize), - Stack { - offset: usize, + StackFrameBase { + offset: isize, + }, + StackTop { + offset: isize, }, Field { object_register: usize, @@ -131,6 +143,6 @@ pub enum Location { Array { array_register: usize, index_register: usize, - offset: Option, + offset: isize, }, } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 27e6b6c..f30bea1 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -43,10 +43,12 @@ pub fn dump_state(state: &DvmState, message: &str) { for (i, register) in state.registers.iter().enumerate() { println!("\tr{:x}: {:?}", i, register); } + println!("Return value register: {}", state.return_value_register); println!("Call stack:"); for call in state.call_stack.iter() { println!("\t{}", call); } + println!("Frame base index: {}", state.frame_base_index); println!("Stack:"); for (i, value) in state.stack.iter().enumerate() { println!("\t{}: {}", i, value); @@ -63,10 +65,13 @@ macro_rules! dvm_panic { pub type PlatformFunction = fn(state: &mut DvmState, context: &DvmContext); +#[derive(Clone)] pub struct DvmState { call_stack: Vec, current_instruction: Option, + frame_base_index: usize, registers: Vec, + return_value_register: DvmValue, stack: Vec, } @@ -75,7 +80,9 @@ impl DvmState { DvmState { call_stack: vec![], current_instruction: None, + frame_base_index: 0, registers: vec![DvmValue::Empty; 16], + return_value_register: DvmValue::Empty, stack: vec![], } } @@ -87,8 +94,14 @@ impl DvmState { } pub fn get_stack_argument(&self, index: usize) -> DvmValue { + let target_index = self + .frame_base_index + .checked_sub(1 + index) + .unwrap_or_else(|| { + dvm_panic!(self, "Unsigned overflow: calculated negative target_index."); + }); self.stack - .get(self.stack.len() - 2 - index) + .get(target_index) .unwrap_or_else(|| { dvm_panic!(self, "Stack underflow!"); }) @@ -150,6 +163,7 @@ impl DvmContext { } } +#[derive(Clone)] pub struct DvmCall { function_name: Rc, source_code_location: SourceCodeLocation, @@ -169,9 +183,9 @@ impl Display for DvmCall { fn update_index(index: &mut usize, offset: isize) { if offset.is_negative() { - *index -= offset.abs() as usize; + *index -= offset.unsigned_abs(); } else { - *index += offset as usize; + *index += offset.unsigned_abs(); } } @@ -193,27 +207,40 @@ fn pop_call_frame(state: &mut DvmState) { fn compute_index_with_offset( registers: &Vec, index_register: usize, - offset: &Option, + offset: isize, ) -> usize { let index = registers[index_register].as_usize().expect(&format!( "Could not convert the value of index_register {} to usize; found {:?}", index_register, registers[index_register] )); - if let Some(o) = offset { - if o.is_negative() { - index - o.unsigned_abs() - } else { - index + o.unsigned_abs() - } + if offset.is_negative() { + index - offset.unsigned_abs() } else { - index + index + offset.unsigned_abs() } } fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { match source { Location::Register(register) => state.registers[*register].clone(), - Location::Stack { offset } => state.stack[*offset].clone(), + Location::StackFrameBase { offset } => { + let index = if offset.is_negative() { + state.frame_base_index - offset.unsigned_abs() + } else { + state.frame_base_index + offset.unsigned_abs() + }; + state.stack[index].clone() + } + Location::StackTop { offset } => { + if *offset >= 0 { + dvm_panic!( + state, + &format!("Offset {} out of bounds (must be negative)", offset) + ); + } + let stack_length = state.stack.len(); + state.stack[stack_length - offset.unsigned_abs()].clone() + } Location::Field { object_register, field_name, @@ -228,7 +255,7 @@ fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue { index_register, offset, } => { - let index = compute_index_with_offset(&state.registers, *index_register, offset); + let index = compute_index_with_offset(&state.registers, *index_register, *offset); state.registers[*array_register].map_array( |a| a.borrow().read_element(index), |v| { @@ -244,8 +271,26 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm Location::Register(register) => { state.registers[*register] = value; } - Location::Stack { offset } => { - state.stack[*offset] = value; + Location::StackFrameBase { offset } => { + let index = if offset.is_negative() { + state.frame_base_index - offset.unsigned_abs() + } else { + state.frame_base_index + offset.unsigned_abs() + }; + state.stack[index] = value; + } + Location::StackTop { offset } => { + if *offset >= 0 { + dvm_panic!( + state, + &format!( + "Stack top offset {} is out of range (must be negative)", + offset + ) + ); + } + let stack_length = state.stack.len(); + state.stack[stack_length - offset.unsigned_abs()] = value; } Location::Field { object_register, @@ -261,7 +306,7 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm index_register, offset, } => { - let index = compute_index_with_offset(&state.registers, *index_register, offset); + let index = compute_index_with_offset(&state.registers, *index_register, *offset); state.registers[*array_register] .expect_array() .borrow_mut() @@ -310,7 +355,9 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue { } pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 { - let main_function = context.static_functions.get(&context.main_function) + let main_function = context + .static_functions + .get(&context.main_function) .expect(&format!("No such main function: {}", context.main_function)); push_call_frame( Rc::new(main_function.fqn().to_string()), @@ -319,23 +366,29 @@ pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 { ); run(main_function.instructions(), state, context); pop_call_frame(state); - state.pop_stack().expect_int_or_else(|v| { - dvm_panic!(state, &format!("Expected DvmValue::Int, but found {}", v)); + state.return_value_register.expect_int_or_else(|v| { + dvm_panic!( + state, + &format!("Expected main to return DvmValue::Int, but found {}", v) + ); }) } // TODO: find all possible unwraps/expects and wrap with call to dvm_panic pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmContext) { + state.frame_base_index = state.stack.len(); let mut index = 0; while index < instructions.len() { - state.current_instruction = Some(instructions[index].clone()); + let current_instruction = &instructions[index]; + state.current_instruction = Some(current_instruction.clone()); + index += 1; use Instruction::*; - match &instructions[index] { + match current_instruction { MoveImmediate { - destination, + destination_register, immediate, } => { - write_to_destination(state, destination, immediate_to_value(immediate)); + state.registers[*destination_register] = immediate_to_value(immediate); } Copy { source, @@ -392,9 +445,18 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont .clone(); // Do call - state.stack.push(DvmValue::Empty); // space for return value + // before: + // - push call frame + // - save current frame base index + // - set current frame base index to current stack size push_call_frame(function_name.clone(), source_code_location.clone(), state); + let saved_frame_base_index = state.frame_base_index; + state.frame_base_index = state.stack.len(); + // actual call run(static_function.instructions(), state, context); + + // reverse order + state.frame_base_index = saved_frame_base_index; pop_call_frame(state); } InvokeObject { @@ -426,12 +488,12 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont let instructions = function.instructions(); // Do call - state.stack.push(DvmValue::Empty); // space for return value - state.stack.push(object_value); // self object push_call_frame(function_name.clone(), source_code_location.clone(), state); + let saved_frame_base_index = state.frame_base_index; + state.frame_base_index = state.stack.len(); run(instructions, state, context); + state.frame_base_index = saved_frame_base_index; pop_call_frame(state); - state.stack.pop(); // self object } InvokeStaticPlatform { function_name, @@ -449,9 +511,11 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont }); // Do call - state.stack.push(DvmValue::Empty); // space for return value push_call_frame(function_name.clone(), source_code_location.clone(), state); + let saved_frame_base_index = state.frame_base_index; + state.frame_base_index = state.stack.len(); platform_function(state, context); + state.frame_base_index = saved_frame_base_index; pop_call_frame(state); } InvokeObjectPlatform { @@ -483,12 +547,22 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont } // Do call - state.stack.push(DvmValue::Empty); // space for return value - state.stack.push(object_value); // self object push_call_frame(function_name.clone(), source_code_location.clone(), state); + let saved_frame_base_index = state.frame_base_index; + state.frame_base_index = state.stack.len(); object_platform_function(state, context); + state.frame_base_index = saved_frame_base_index; pop_call_frame(state); - state.stack.pop(); // self object + } + SetReturnValue { source_register } => { + state.return_value_register = + std::mem::take(&mut state.registers[*source_register]); + } + TakeReturnValue { + destination_register, + } => { + state.registers[*destination_register] = + std::mem::take(&mut state.return_value_register); } Add { .. } => {} Subtract { .. } => {} @@ -518,7 +592,7 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont Return => { break; } + DumpState { message } => dump_state(state, message), } - index += 1; } }