diff --git a/dm/src/repl.rs b/dm/src/repl.rs index 0c134d6..eb1a457 100644 --- a/dm/src/repl.rs +++ b/dm/src/repl.rs @@ -10,7 +10,7 @@ use dmc_lib::symbol_table::SymbolTable; use dmc_lib::token::TokenKind; use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::function::Function; -use dvm_lib::vm::value::Value; +use dvm_lib::vm::operand::Operand; use dvm_lib::vm::{CallStack, DvmContext, call}; use std::io; use std::io::Write; @@ -76,7 +76,7 @@ pub fn repl(register_count: usize) { ); } - let mut registers = vec![Value::Null; register_count]; + let mut registers = vec![Operand::Null; register_count]; let mut call_stack = CallStack::new(); let result = call(&context, &mut registers, &mut call_stack, "__repl", &[]); diff --git a/dm/src/run.rs b/dm/src/run.rs index 5c273a2..50d6a5c 100644 --- a/dm/src/run.rs +++ b/dm/src/run.rs @@ -9,7 +9,7 @@ use dmc_lib::parser::parse_compilation_unit; use dmc_lib::symbol_table::SymbolTable; use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::function::Function; -use dvm_lib::vm::value::Value; +use dvm_lib::vm::operand::Operand; use dvm_lib::vm::{CallStack, DvmContext, call}; use std::path::PathBuf; @@ -92,7 +92,7 @@ pub fn run(script: &PathBuf, show_ir: bool, show_asm: bool, register_count: usiz ); } - let mut registers: Vec = vec![Value::Null; register_count]; + let mut registers: Vec = vec![Operand::Null; register_count]; let mut call_stack = CallStack::new(); let result = call( diff --git a/dmc-lib/src/ast/constructor.rs b/dmc-lib/src/ast/constructor.rs index bb4c5dd..664b17b 100644 --- a/dmc-lib/src/ast/constructor.rs +++ b/dmc-lib/src/ast/constructor.rs @@ -7,6 +7,7 @@ use crate::ir::ir_allocate::IrAllocate; use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; use crate::ir::ir_function::IrFunction; +use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut; use crate::ir::ir_operation::IrOperation; use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_set_field::IrSetField; @@ -220,10 +221,40 @@ impl Constructor { // next, initialize fields that have an initializer in their declaration for field in fields { if let Some(initializer) = field.initializer() { + // get a mut ref to the field + let ir_get_field_ref_mut = IrGetFieldRefMut::new( + self_variable.clone(), + field.field_symbol().borrow().field_index(), + ); + let field_mut_ref_variable_name: Rc = ir_builder.new_t_var().into(); + let field_mut_ref_variable = Rc::new(RefCell::new(IrVariable::new_vr( + field_mut_ref_variable_name.clone(), + ir_builder.current_block().id(), + field.field_symbol().borrow().type_info(), + ))); + let field_mut_ref_assign = IrAssign::new( + field_mut_ref_variable.clone(), + IrOperation::GetFieldRefMut(ir_get_field_ref_mut), + ); + ir_builder + .current_block_mut() + .add_statement(IrStatement::Assign(field_mut_ref_assign)); + + // save the mut ref to the builder for other uses if needed + ir_builder + .field_mut_pointer_variables_mut() + .insert(field_mut_ref_variable_name.clone(), field_mut_ref_variable); + + // now write the initializer result to the field + let field_mut_ref_variable = ir_builder + .field_mut_pointer_variables() + .get(&field_mut_ref_variable_name) + .unwrap() + .clone(); + let ir_expression = initializer.to_ir(&mut ir_builder, symbol_table).unwrap(); let ir_set_field = IrSetField::new( - &self_variable.clone(), - field.field_symbol().borrow().field_index(), + &field_mut_ref_variable, // dumb that we clone it and then ref it ir_expression, ); ir_builder diff --git a/dmc-lib/src/ast/ir_builder.rs b/dmc-lib/src/ast/ir_builder.rs index a6483bb..28878f0 100644 --- a/dmc-lib/src/ast/ir_builder.rs +++ b/dmc-lib/src/ast/ir_builder.rs @@ -13,6 +13,8 @@ pub struct IrBuilder { blocks: HashMap>>, current_block_builder: Option, self_variable: Option>>, + field_variables: HashMap, Rc>>, + mut_field_variables: HashMap, Rc>>, } impl IrBuilder { @@ -24,6 +26,8 @@ impl IrBuilder { blocks: HashMap::new(), current_block_builder: None, self_variable: None, + field_variables: HashMap::new(), + mut_field_variables: HashMap::new(), } } @@ -83,6 +87,26 @@ impl IrBuilder { pub fn self_variable(&self) -> &Rc> { self.self_variable.as_ref().unwrap() } + + pub fn field_pointer_variables(&self) -> &HashMap, Rc>> { + &self.field_variables + } + + pub fn field_pointer_variables_mut( + &mut self, + ) -> &mut HashMap, Rc>> { + &mut self.field_variables + } + + pub fn field_mut_pointer_variables(&self) -> &HashMap, Rc>> { + &self.mut_field_variables + } + + pub fn field_mut_pointer_variables_mut( + &mut self, + ) -> &mut HashMap, Rc>> { + &mut self.mut_field_variables + } } pub struct IrBlockBuilder { diff --git a/dmc-lib/src/ast/negative_expression.rs b/dmc-lib/src/ast/negative_expression.rs index c87353b..4aaa0ef 100644 --- a/dmc-lib/src/ast/negative_expression.rs +++ b/dmc-lib/src/ast/negative_expression.rs @@ -74,9 +74,6 @@ impl NegativeExpression { .expect("Attempt to negate non-value expression"); match operand_as_ir { - IrExpression::Field(self_variable, _) => { - todo!() - } IrExpression::Parameter(parameter) => { let destination = Rc::new(RefCell::new(IrVariable::new_vr( builder.new_t_var().into(), diff --git a/dmc-lib/src/ir/ir_assign.rs b/dmc-lib/src/ir/ir_assign.rs index 9285cdf..0692966 100644 --- a/dmc-lib/src/ir/ir_assign.rs +++ b/dmc-lib/src/ir/ir_assign.rs @@ -3,7 +3,7 @@ use crate::ir::assemble::{Assemble, InstructionsBuilder}; use crate::ir::ir_operation::IrOperation; use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor}; use crate::ir::register_allocation::{OffsetCounter, VrUser}; -use dvm_lib::instruction::{Instruction, Location}; +use dvm_lib::instruction::Instruction; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; @@ -79,16 +79,41 @@ impl VrUser for IrAssign { impl Assemble for IrAssign { fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { - let destination = match self.destination.borrow().descriptor() { - IrVariableDescriptor::VirtualRegister(vr_variable) => { - Location::Register(vr_variable.assigned_register()) - } - IrVariableDescriptor::Stack(stack_variable) => { - Location::StackFrameOffset(stack_variable.offset()) - } - }; + let destination = self.destination.borrow().descriptor().as_location(); match self.initializer.as_ref() { + IrOperation::GetFieldRef(ir_get_field_ref) => { + let self_location = ir_get_field_ref + .self_variable() + .borrow() + .descriptor() + .as_location(); + builder.push(Instruction::GetFieldPointer( + self_location, + ir_get_field_ref.field_index(), + destination, + )); + } + IrOperation::GetFieldRefMut(ir_get_field_ref) => { + let self_location = ir_get_field_ref + .self_variable() + .borrow() + .descriptor() + .as_location(); + builder.push(Instruction::GetFieldPointerMut( + self_location, + ir_get_field_ref.field_index(), + destination, + )); + } + IrOperation::ReadField(ir_read_field) => { + let field_ref_location = ir_read_field + .field_ref_variable() + .borrow() + .descriptor() + .as_location(); + builder.push(Instruction::ReadField(field_ref_location, destination)); + } IrOperation::Load(ir_expression) => { let move_operand = ir_expression.move_operand(constants_table); builder.push(Instruction::Move(move_operand, destination)); diff --git a/dmc-lib/src/ir/ir_expression.rs b/dmc-lib/src/ir/ir_expression.rs index 88fa005..b228cea 100644 --- a/dmc-lib/src/ir/ir_expression.rs +++ b/dmc-lib/src/ir/ir_expression.rs @@ -1,5 +1,4 @@ use crate::constants_table::ConstantsTable; -use crate::ir::assemble::InstructionsBuilder; use crate::ir::ir_parameter::IrParameter; use crate::ir::ir_variable::{ IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor, @@ -16,7 +15,6 @@ use std::fmt::{Display, Formatter}; use std::rc::Rc; pub enum IrExpression { - Field(Rc>, usize), Parameter(Rc), Variable(Rc>), Int(i32), @@ -27,19 +25,6 @@ pub enum IrExpression { impl IrExpression { pub fn move_operand(&self, constants_table: &mut ConstantsTable) -> MoveOperand { match self { - IrExpression::Field(self_variable, field_index) => { - match self_variable.borrow().descriptor() { - IrVariableDescriptor::VirtualRegister(register_self_variable) => { - MoveOperand::Location(Location::RegisterField( - register_self_variable.assigned_register(), - *field_index, - )) - } - IrVariableDescriptor::Stack(stack_self_variable) => MoveOperand::Location( - Location::StackFrameOffsetField(stack_self_variable.offset(), *field_index), - ), - } - } IrExpression::Parameter(ir_parameter) => { MoveOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -62,9 +47,6 @@ impl IrExpression { pub fn push_operand(&self, constants_table: &mut ConstantsTable) -> PushOperand { match self { - IrExpression::Field(self_variable, _) => { - todo!() - } IrExpression::Parameter(ir_parameter) => { PushOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -87,9 +69,6 @@ impl IrExpression { pub fn add_operand(&self, constants_table: &mut ConstantsTable) -> AddOperand { match self { - IrExpression::Field(self_variable, _) => { - todo!() - } IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() { TypeInfo::Integer | TypeInfo::Double | TypeInfo::String => { AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) @@ -128,9 +107,6 @@ impl IrExpression { pub fn subtract_operand(&self) -> SubtractOperand { match self { - IrExpression::Field(self_variable, _) => { - todo!() - } IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() { TypeInfo::Integer | TypeInfo::Double => SubtractOperand::Location( Location::StackFrameOffset(ir_parameter.stack_offset()), @@ -166,9 +142,6 @@ impl IrExpression { pub fn multiply_operand(&self) -> MultiplyOperand { match self { - IrExpression::Field(self_variable, _) => { - todo!() - } IrExpression::Parameter(ir_parameter) => { MultiplyOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -190,19 +163,6 @@ impl IrExpression { pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand { match self { - IrExpression::Field(self_variable, field_index) => { - match self_variable.borrow().descriptor() { - IrVariableDescriptor::VirtualRegister(self_register_variable) => { - ReturnOperand::Location(Location::RegisterField( - self_register_variable.assigned_register(), - *field_index, - )) - } - IrVariableDescriptor::Stack(self_stack_variable) => ReturnOperand::Location( - Location::StackFrameOffsetField(self_stack_variable.offset(), *field_index), - ), - } - } IrExpression::Parameter(ir_parameter) => { ReturnOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -227,9 +187,6 @@ impl IrExpression { pub fn set_field_operand(&self, constants_table: &mut ConstantsTable) -> SetFieldOperand { match self { - IrExpression::Field(self_variable, _) => { - todo!() - } IrExpression::Parameter(ir_parameter) => { SetFieldOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset())) } @@ -254,9 +211,6 @@ impl IrExpression { impl Display for IrExpression { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - IrExpression::Field(self_variable, field_index) => { - write!(f, "{}.{}", self_variable.borrow(), field_index) - } IrExpression::Parameter(ir_parameter) => { write!(f, "{}", ir_parameter) } @@ -284,15 +238,6 @@ impl VrUser for IrExpression { fn vr_uses(&self) -> HashSet { match self { - IrExpression::Field(self_variable, field_index) => { - if let IrVariableDescriptor::VirtualRegister(vr_variable) = - self_variable.borrow().descriptor() - { - HashSet::from([vr_variable.clone()]) - } else { - HashSet::new() - } - } IrExpression::Parameter(_) => HashSet::new(), IrExpression::Variable(ir_variable) => { if let IrVariableDescriptor::VirtualRegister(vr_variable) = @@ -311,9 +256,6 @@ impl VrUser for IrExpression { fn propagate_spills(&mut self, spills: &HashSet) { match self { - IrExpression::Field(self_variable, field_index) => { - // no-op, no defs - } IrExpression::Parameter(_) => { // no-op } @@ -350,9 +292,6 @@ impl VrUser for IrExpression { assignments: &HashMap, ) { match self { - IrExpression::Field(self_variable, field_index) => { - // no-op - } IrExpression::Parameter(_) => { // no-op } diff --git a/dmc-lib/src/ir/ir_get_field_ref.rs b/dmc-lib/src/ir/ir_get_field_ref.rs new file mode 100644 index 0000000..76f1cee --- /dev/null +++ b/dmc-lib/src/ir/ir_get_field_ref.rs @@ -0,0 +1,59 @@ +use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor}; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +pub struct IrGetFieldRef { + self_variable: Rc>, + field_index: usize, +} + +impl IrGetFieldRef { + pub fn new(self_variable: Rc>, field_index: usize) -> Self { + Self { + self_variable, + field_index, + } + } + + pub fn self_variable(&self) -> &Rc> { + &self.self_variable + } + + pub fn field_index(&self) -> usize { + self.field_index + } +} + +impl Display for IrGetFieldRef { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "&{}.{}", self.self_variable.borrow(), self.field_index) + } +} + +impl VrUser for IrGetFieldRef { + fn vr_definitions(&self) -> HashSet { + HashSet::new() + } + + fn vr_uses(&self) -> HashSet { + match self.self_variable.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(vr_variable) => { + HashSet::from([vr_variable.clone()]) + } + IrVariableDescriptor::Stack(_) => HashSet::new(), + } + } + + fn propagate_spills(&mut self, spills: &HashSet) {} + + fn propagate_register_assignments( + &mut self, + assignments: &HashMap, + ) { + } + + fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {} +} diff --git a/dmc-lib/src/ir/ir_get_field_ref_mut.rs b/dmc-lib/src/ir/ir_get_field_ref_mut.rs new file mode 100644 index 0000000..f5b8b8a --- /dev/null +++ b/dmc-lib/src/ir/ir_get_field_ref_mut.rs @@ -0,0 +1,64 @@ +use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor}; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +pub struct IrGetFieldRefMut { + self_variable: Rc>, + field_index: usize, +} + +impl IrGetFieldRefMut { + pub fn new(self_variable: Rc>, field_index: usize) -> Self { + Self { + self_variable, + field_index, + } + } + + pub fn self_variable(&self) -> &Rc> { + &self.self_variable + } + + pub fn field_index(&self) -> usize { + self.field_index + } +} + +impl Display for IrGetFieldRefMut { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "&mut {}.{}", + self.self_variable.borrow(), + self.field_index() + ) + } +} + +impl VrUser for IrGetFieldRefMut { + fn vr_definitions(&self) -> HashSet { + HashSet::new() + } + + fn vr_uses(&self) -> HashSet { + match self.self_variable.borrow().descriptor() { + IrVariableDescriptor::VirtualRegister(vr_variable) => { + HashSet::from([vr_variable.clone()]) + } + IrVariableDescriptor::Stack(stack_variable) => HashSet::new(), + } + } + + fn propagate_spills(&mut self, spills: &HashSet) {} + + fn propagate_register_assignments( + &mut self, + assignments: &HashMap, + ) { + } + + fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {} +} diff --git a/dmc-lib/src/ir/ir_operation.rs b/dmc-lib/src/ir/ir_operation.rs index ac8cd93..919cefc 100644 --- a/dmc-lib/src/ir/ir_operation.rs +++ b/dmc-lib/src/ir/ir_operation.rs @@ -2,7 +2,10 @@ use crate::ir::ir_add::IrAdd; use crate::ir::ir_allocate::IrAllocate; use crate::ir::ir_call::IrCall; use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_get_field_ref::IrGetFieldRef; +use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut; use crate::ir::ir_multiply::IrMultiply; +use crate::ir::ir_read_field::IrReadField; use crate::ir::ir_subtract::IrSubtract; use crate::ir::ir_variable::IrVrVariableDescriptor; use crate::ir::register_allocation::{OffsetCounter, VrUser}; @@ -10,6 +13,9 @@ use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; pub enum IrOperation { + GetFieldRef(IrGetFieldRef), + GetFieldRefMut(IrGetFieldRefMut), + ReadField(IrReadField), Load(IrExpression), Add(IrAdd), Subtract(IrSubtract), @@ -21,6 +27,15 @@ pub enum IrOperation { impl Display for IrOperation { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { + IrOperation::GetFieldRef(ir_get_field_ref) => { + write!(f, "{}", ir_get_field_ref) + } + IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => { + write!(f, "{}", ir_get_field_ref_mut) + } + IrOperation::ReadField(ir_read_field) => { + write!(f, "{}", ir_read_field) + } IrOperation::Load(ir_expression) => { write!(f, "{}", ir_expression) } @@ -46,6 +61,9 @@ impl Display for IrOperation { impl VrUser for IrOperation { fn vr_definitions(&self) -> HashSet { match self { + IrOperation::GetFieldRef(_) => HashSet::new(), + IrOperation::GetFieldRefMut(_) => HashSet::new(), + IrOperation::ReadField(_) => HashSet::new(), IrOperation::Load(ir_expression) => ir_expression.vr_definitions(), IrOperation::Add(ir_add) => ir_add.vr_definitions(), IrOperation::Subtract(ir_subtract) => ir_subtract.vr_definitions(), @@ -57,6 +75,9 @@ impl VrUser for IrOperation { fn vr_uses(&self) -> HashSet { match self { + IrOperation::GetFieldRef(ir_get_field_ref) => ir_get_field_ref.vr_uses(), + IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => ir_get_field_ref_mut.vr_uses(), + IrOperation::ReadField(ir_read_field) => ir_read_field.vr_uses(), IrOperation::Load(ir_expression) => ir_expression.vr_uses(), IrOperation::Add(ir_add) => ir_add.vr_uses(), IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(), @@ -68,6 +89,9 @@ impl VrUser for IrOperation { fn propagate_spills(&mut self, spills: &HashSet) { match self { + IrOperation::GetFieldRef(_) => {} + IrOperation::GetFieldRefMut(_) => {} + IrOperation::ReadField(_) => {} IrOperation::Load(ir_expression) => { ir_expression.propagate_spills(spills); } @@ -92,6 +116,9 @@ impl VrUser for IrOperation { assignments: &HashMap, ) { match self { + IrOperation::GetFieldRef(_) => {} + IrOperation::GetFieldRefMut(_) => {} + IrOperation::ReadField(_) => {} IrOperation::Load(ir_expression) => { ir_expression.propagate_register_assignments(assignments); } diff --git a/dmc-lib/src/ir/ir_read_field.rs b/dmc-lib/src/ir/ir_read_field.rs new file mode 100644 index 0000000..2e13670 --- /dev/null +++ b/dmc-lib/src/ir/ir_read_field.rs @@ -0,0 +1,52 @@ +use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor}; +use crate::ir::register_allocation::{OffsetCounter, VrUser}; +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::fmt::{Display, Formatter}; +use std::rc::Rc; + +pub struct IrReadField { + field_ref_variable: Rc>, +} + +impl IrReadField { + pub fn new(field_ref_variable: Rc>) -> Self { + Self { field_ref_variable } + } + + pub fn field_ref_variable(&self) -> &Rc> { + &self.field_ref_variable + } +} + +impl Display for IrReadField { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.field_ref_variable.borrow(),) + } +} + +impl VrUser for IrReadField { + fn vr_definitions(&self) -> HashSet { + HashSet::new() + } + + fn vr_uses(&self) -> HashSet { + let mut set = HashSet::new(); + if let IrVariableDescriptor::VirtualRegister(vr_variable) = + self.field_ref_variable.borrow().descriptor() + { + set.insert(vr_variable.clone()); + } + set + } + + fn propagate_spills(&mut self, spills: &HashSet) {} + + fn propagate_register_assignments( + &mut self, + assignments: &HashMap, + ) { + } + + fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {} +} diff --git a/dmc-lib/src/ir/ir_set_field.rs b/dmc-lib/src/ir/ir_set_field.rs index de0a9ec..ed5d0e7 100644 --- a/dmc-lib/src/ir/ir_set_field.rs +++ b/dmc-lib/src/ir/ir_set_field.rs @@ -4,27 +4,21 @@ use crate::ir::ir_expression::IrExpression; use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor}; use crate::ir::register_allocation::{OffsetCounter, VrUser}; use crate::ir::util::propagate_spills; -use dvm_lib::instruction::{Instruction, Location}; +use dvm_lib::instruction::Instruction; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::{Display, Formatter}; use std::rc::Rc; pub struct IrSetField { - target_object: Rc>, - field_index: usize, + field_ref_variable: Rc>, initializer: Box, } impl IrSetField { - pub fn new( - target_object: &Rc>, - field_index: usize, - initializer: IrExpression, - ) -> Self { + pub fn new(field_ref_variable: &Rc>, initializer: IrExpression) -> Self { Self { - target_object: target_object.clone(), - field_index, + field_ref_variable: field_ref_variable.clone(), initializer: initializer.into(), } } @@ -38,7 +32,7 @@ impl VrUser for IrSetField { fn vr_uses(&self) -> HashSet { let mut set = HashSet::new(); - match self.target_object.borrow().descriptor() { + match self.field_ref_variable.borrow().descriptor() { IrVariableDescriptor::VirtualRegister(vr_variable) => { set.insert(vr_variable.clone()); } @@ -49,7 +43,7 @@ impl VrUser for IrSetField { } fn propagate_spills(&mut self, spills: &HashSet) { - propagate_spills(&mut self.target_object, spills); + propagate_spills(&mut self.field_ref_variable, spills); self.initializer.propagate_spills(spills); } @@ -67,21 +61,9 @@ impl VrUser for IrSetField { impl Assemble for IrSetField { fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { - let destination = match self.target_object.borrow().descriptor() { - IrVariableDescriptor::VirtualRegister(vr_variable) => { - Location::Register(vr_variable.assigned_register()) - } - IrVariableDescriptor::Stack(stack_variable) => { - Location::StackFrameOffset(stack_variable.offset()) - } - }; - + let field_ref_location = self.field_ref_variable.borrow().descriptor().as_location(); let set_field_operand = self.initializer.set_field_operand(constants_table); - builder.push(Instruction::SetField( - destination, - self.field_index, - set_field_operand, - )); + builder.push(Instruction::SetField(field_ref_location, set_field_operand)); } } @@ -89,9 +71,8 @@ impl Display for IrSetField { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, - "{}.{} = {}", - self.target_object.borrow(), - self.field_index, + "*{} = {}", + self.field_ref_variable.borrow(), self.initializer ) } diff --git a/dmc-lib/src/ir/ir_variable.rs b/dmc-lib/src/ir/ir_variable.rs index 63b49b3..f36b1ed 100644 --- a/dmc-lib/src/ir/ir_variable.rs +++ b/dmc-lib/src/ir/ir_variable.rs @@ -1,4 +1,5 @@ use crate::type_info::TypeInfo; +use dvm_lib::instruction::Location; use std::fmt::{Debug, Display, Formatter}; use std::hash::Hash; use std::rc::Rc; @@ -80,6 +81,15 @@ impl IrVariableDescriptor { IrVariableDescriptor::Stack(stack_variable) => stack_variable.name_owned(), } } + + pub fn as_location(&self) -> Location { + match self { + IrVariableDescriptor::VirtualRegister(register_variable) => { + register_variable.as_location() + } + IrVariableDescriptor::Stack(stack_variable) => stack_variable.as_location(), + } + } } #[derive(Clone, Hash, PartialEq, Eq)] @@ -117,6 +127,10 @@ impl IrVrVariableDescriptor { pub fn assigned_register(&self) -> usize { self.assigned_register.unwrap() } + + pub fn as_location(&self) -> Location { + Location::Register(self.assigned_register.unwrap()) + } } impl Display for IrVrVariableDescriptor { @@ -161,6 +175,10 @@ impl IrStackVariableDescriptor { pub fn offset(&self) -> isize { self.offset.unwrap() } + + pub fn as_location(&self) -> Location { + Location::StackFrameOffset(self.offset.unwrap()) + } } impl Display for IrStackVariableDescriptor { diff --git a/dmc-lib/src/ir/mod.rs b/dmc-lib/src/ir/mod.rs index e8b120a..1248fc8 100644 --- a/dmc-lib/src/ir/mod.rs +++ b/dmc-lib/src/ir/mod.rs @@ -6,9 +6,12 @@ pub mod ir_block; pub mod ir_call; pub mod ir_expression; pub mod ir_function; +pub mod ir_get_field_ref; +pub mod ir_get_field_ref_mut; pub mod ir_multiply; pub mod ir_operation; pub mod ir_parameter; +pub mod ir_read_field; pub mod ir_return; pub mod ir_set_field; pub mod ir_statement; diff --git a/dmc-lib/src/symbol/expressible_symbol.rs b/dmc-lib/src/symbol/expressible_symbol.rs index 46e9302..9ad5762 100644 --- a/dmc-lib/src/symbol/expressible_symbol.rs +++ b/dmc-lib/src/symbol/expressible_symbol.rs @@ -1,5 +1,12 @@ use crate::ast::ir_builder::IrBuilder; +use crate::ir::ir_assign::IrAssign; use crate::ir::ir_expression::IrExpression; +use crate::ir::ir_get_field_ref::IrGetFieldRef; +use crate::ir::ir_operation::IrOperation; +use crate::ir::ir_read_field::IrReadField; +use crate::ir::ir_statement::IrStatement; +use crate::ir::ir_variable::IrVariable; +use crate::symbol::Symbol; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol::field_symbol::FieldSymbol; use crate::symbol::function_symbol::FunctionSymbol; @@ -39,10 +46,58 @@ impl ExpressibleSymbol { ExpressibleSymbol::Class(class_symbol) => { todo!() } - ExpressibleSymbol::Field(field_symbol) => IrExpression::Field( - builder.self_variable().clone(), - field_symbol.borrow().field_index(), - ), + ExpressibleSymbol::Field(field_symbol) => { + // This following should work because blocks are flat in the ir; if a variable is + // defined in the ir block from this point forward, it's available to all subsequent + // blocks. + if !builder + .field_pointer_variables() + .contains_key(field_symbol.borrow().declared_name()) + { + let field_ref_variable = IrVariable::new_vr( + builder.new_t_var().into(), + builder.current_block().id(), + field_symbol.borrow().type_info(), + ); + let as_rc = Rc::new(RefCell::new(field_ref_variable)); + let to_insert = as_rc.clone(); + let self_variable = builder.self_variable().clone(); + builder + .current_block_mut() + .add_statement(IrStatement::Assign(IrAssign::new( + as_rc, + IrOperation::GetFieldRef(IrGetFieldRef::new( + self_variable, + field_symbol.borrow().field_index(), + )), + ))); + builder + .field_pointer_variables_mut() + .insert(field_symbol.borrow().declared_name_owned(), to_insert); + } + // now we need to read the field into a variable and return an expression pointing + // to that variable + let read_destination = IrVariable::new_vr( + builder.new_t_var().into(), + builder.current_block().id(), + field_symbol.borrow().type_info(), + ); + let read_destination_as_rc = Rc::new(RefCell::new(read_destination)); + let ir_read_field = IrReadField::new( + builder + .field_pointer_variables() + .get(field_symbol.borrow().declared_name()) + .unwrap() + .clone(), + ); + builder + .current_block_mut() + .add_statement(IrStatement::Assign(IrAssign::new( + read_destination_as_rc.clone(), + IrOperation::ReadField(ir_read_field), + ))); + IrExpression::Variable(read_destination_as_rc) + } ExpressibleSymbol::Function(_) => { panic!("Cannot get ir_variable for FunctionSymbol"); } diff --git a/dvm-lib/src/instruction.rs b/dvm-lib/src/instruction.rs index 7a2f1de..f5cea84 100644 --- a/dvm-lib/src/instruction.rs +++ b/dvm-lib/src/instruction.rs @@ -18,8 +18,18 @@ pub enum Instruction { InvokePlatformStatic(FunctionName, ArgCount), Allocate(ClassFqn, Location), - GetField(Location, FieldIndex, Location), - SetField(Location, FieldIndex, SetFieldOperand), + + /// (self_location, field_index, destination) + GetFieldPointer(Location, FieldIndex, Location), + + /// (self_location, field_index, destination) + GetFieldPointerMut(Location, FieldIndex, Location), + + /// (field_pointer_location, destination) + ReadField(Location, Location), + + /// (field_pointer_mut_location, operand) + SetField(Location, SetFieldOperand), Add(AddOperand, AddOperand, Location), Subtract(SubtractOperand, SubtractOperand, Location), @@ -73,11 +83,26 @@ impl Display for Instruction { Instruction::Allocate(class_fqn, location) => { write!(f, "alloc {}, {}", class_fqn, location) } - Instruction::GetField(source, field_index, destination) => { - write!(f, "getf {}.{}, {}", source, field_index, destination) + + Instruction::GetFieldPointer(self_location, field_index, destination) => { + write!( + f, + "getf &{}.{}, {}", + self_location, field_index, destination + ) } - Instruction::SetField(target_location, field_index, operand) => { - write!(f, "setf {}.{}, {}", target_location, field_index, operand) + Instruction::GetFieldPointerMut(self_location, field_index, destination) => { + write!( + f, + "getf &mut {}.{}, {}", + self_location, field_index, destination + ) + } + Instruction::ReadField(field_pointer_location, destination) => { + write!(f, "readf *{}, {}", field_pointer_location, destination) + } + Instruction::SetField(self_location, destination) => { + write!(f, "setf {}, {}", self_location, destination) } } } @@ -86,8 +111,6 @@ impl Display for Instruction { pub enum Location { Register(Register), StackFrameOffset(StackFrameOffset), - RegisterField(Register, FieldIndex), - StackFrameOffsetField(StackFrameOffset, FieldIndex), } impl Display for Location { @@ -103,16 +126,6 @@ impl Display for Location { write!(f, "fp{}", offset) } } - Location::RegisterField(register, field_index) => { - write!(f, "r{}.{}", register, field_index) - } - Location::StackFrameOffsetField(offset, field_index) => { - if offset.is_positive() || *offset == 0 { - write!(f, "fp+{}.{}", offset, field_index) - } else { - write!(f, "fp-{}.{}", offset, field_index) - } - } } } } diff --git a/dvm-lib/src/vm/instruction_helpers.rs b/dvm-lib/src/vm/instruction_helpers.rs deleted file mode 100644 index 3889938..0000000 --- a/dvm-lib/src/vm/instruction_helpers.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::instruction::{AddOperand, MultiplyOperand, SubtractOperand}; -use crate::vm::CallFrame; -use crate::vm::constant::Constant; -use crate::vm::value::Value; -use crate::vm::value_util::{load_constant_value, load_value}; -use std::collections::HashMap; -use std::rc::Rc; - -pub fn add_operand_to_value( - add_operand: &AddOperand, - registers: &[Value], - current_frame: &CallFrame, - constants: &HashMap, Constant>, -) -> Value { - match add_operand { - AddOperand::Location(location) => load_value( - registers, - current_frame.stack(), - current_frame.fp(), - location, - ) - .clone(), - AddOperand::Int(i) => Value::Int(*i), - AddOperand::Double(d) => Value::Double(*d), - AddOperand::String(constant_name) => load_constant_value(constants, constant_name), - } -} - -pub fn subtract_operand_to_value( - subtract_operand: &SubtractOperand, - registers: &[Value], - current_frame: &CallFrame, -) -> Value { - match subtract_operand { - SubtractOperand::Location(location) => load_value( - registers, - current_frame.stack(), - current_frame.fp(), - location, - ) - .clone(), - SubtractOperand::Int(i) => Value::Int(*i), - SubtractOperand::Double(d) => Value::Double(*d), - } -} - -pub fn multiply_operand_to_value( - multiply_operand: &MultiplyOperand, - registers: &[Value], - current_frame: &CallFrame, -) -> Value { - match multiply_operand { - MultiplyOperand::Location(location) => load_value( - registers, - current_frame.stack(), - current_frame.fp(), - location, - ) - .clone(), - MultiplyOperand::Int(i) => Value::Int(*i), - MultiplyOperand::Double(d) => Value::Double(*d), - } -} diff --git a/dvm-lib/src/vm/mod.rs b/dvm-lib/src/vm/mod.rs index e1e1f61..261db3f 100644 --- a/dvm-lib/src/vm/mod.rs +++ b/dvm-lib/src/vm/mod.rs @@ -1,21 +1,25 @@ -use crate::instruction::{Instruction, MoveOperand, PushOperand, ReturnOperand}; +use crate::instruction::Instruction; use crate::platform_function::PlatformFunction; use crate::vm::constant::Constant; use crate::vm::function::Function; -use crate::vm::instruction_helpers::{ - add_operand_to_value, multiply_operand_to_value, subtract_operand_to_value, +use crate::vm::operand::Operand; +use crate::vm::operand_helpers::{ + add_operand_to_value, move_operand_to_value, multiply_operand_to_value, push_operand_to_value, + return_operand_to_value, set_field_operand_to_value, subtract_operand_to_value, }; +use crate::vm::util::*; use crate::vm::value::Value; -use crate::vm::value_util::*; use std::collections::HashMap; +use std::ptr; use std::rc::Rc; pub mod constant; pub mod function; -mod instruction_helpers; pub mod object; +pub mod operand; +mod operand_helpers; +mod util; pub mod value; -mod value_util; pub struct DvmContext { functions: HashMap, Function>, @@ -61,7 +65,7 @@ pub struct CallFrame<'a> { function: &'a Function, instructions: &'a Vec, ip: usize, - stack: Vec, + stack: Vec, fp: usize, return_value: Option, } @@ -94,11 +98,11 @@ impl<'a> CallFrame<'a> { self.ip += 1; } - fn stack(&self) -> &[Value] { + fn stack(&self) -> &[Operand] { &self.stack } - fn stack_mut(&mut self) -> &mut Vec { + fn stack_mut(&mut self) -> &mut Vec { &mut self.stack } @@ -171,7 +175,7 @@ impl<'a> CallStack<'a> { pub fn call<'a>( context: &'a DvmContext, - registers: &mut Vec, + registers: &mut Vec, call_stack: &mut CallStack<'a>, function_name: &str, arguments: &[Value], @@ -191,7 +195,10 @@ pub fn call<'a>( // put each arg on the stack for argument in arguments { - call_stack.top_mut().stack_mut().push(argument.clone()); + call_stack + .top_mut() + .stack_mut() + .push(Operand::Value(argument.clone())); } // set fp for this function @@ -200,7 +207,7 @@ pub fn call<'a>( // ensure enough stack space call_stack.top_mut().stack_mut().resize( arguments.len() + (function.stack_size() as usize), - Value::Null, + Operand::Null, ); // container for final return value @@ -219,41 +226,21 @@ pub fn call<'a>( Instruction::Move(source, destination) => { // move a value to a destination // could be a copy or an immediate - let value = match source { - MoveOperand::Location(location) => load_value( - registers, - call_stack.top().stack(), - call_stack.top().fp(), - location, - ) - .clone(), - MoveOperand::Int(i) => Value::Int(*i), - MoveOperand::Double(d) => Value::Double(*d), - MoveOperand::String(constant_name) => { - load_constant_value(context.constants(), constant_name) - } - }; + let value = + move_operand_to_value(source, registers, call_stack.top(), context.constants()); put_value(registers, call_stack.top_mut(), destination, value); call_stack.top_mut().increment_ip(); } /* Push instructions */ Instruction::Push(operand) => { - let value = match operand { - PushOperand::Location(location) => load_value( - registers, - call_stack.top().stack(), - call_stack.top().fp(), - location, - ) - .clone(), - PushOperand::Double(d) => Value::Double(*d), - PushOperand::Int(i) => Value::Int(*i), - PushOperand::String(constant_name) => { - load_constant_value(context.constants(), constant_name) - } - }; - call_stack.top_mut().stack_mut().push(value); + let value = push_operand_to_value( + operand, + registers, + call_stack.top(), + context.constants(), + ); + call_stack.top_mut().stack_mut().push(Operand::Value(value)); call_stack.top_mut().increment_ip(); } @@ -265,8 +252,13 @@ pub fn call<'a>( .expect(&format!("Function {} not found", function_name)); // get args - let mut args = - call_stack.top().stack()[call_stack.top().stack().len() - arg_count..].to_vec(); + // this isn't perfect (yet), but for now it works and satisfies the borrow checkers + let mut args = call_stack.top().stack() + [call_stack.top().stack().len() - arg_count..] + .iter() + .map(|operand| operand.unwrap_value().clone()) + .map(|value| Operand::Value(value)) + .collect::>(); // save registers for register in registers.iter_mut() { @@ -287,7 +279,7 @@ pub fn call<'a>( call_stack .top_mut() .stack_mut() - .resize(arg_count + (function.stack_size() as usize), Value::Null); + .resize(arg_count + (function.stack_size() as usize), Operand::Null); // set fp for callee frame let callee_frame = call_stack.top_mut(); @@ -300,14 +292,22 @@ pub fn call<'a>( .get(function_name) .expect(&format!("Platform function {} not found", function_name)); - let args = &call_stack.top().stack()[call_stack.top().stack().len() - arg_count..]; + let arg_operands = + &call_stack.top().stack()[call_stack.top().stack().len() - arg_count..]; + let args = arg_operands + .iter() + .map(|operand| operand.unwrap_value().clone()) + .collect::>(); - let result = platform_function(args); + let result = platform_function(&args); match result { Ok(return_value) => { // push return value to top of caller stack if it's not null if !matches!(return_value, Value::Null) { - call_stack.top_mut().stack_mut().push(return_value); + call_stack + .top_mut() + .stack_mut() + .push(Operand::Value(return_value)); } } Err(error) => { @@ -327,18 +327,77 @@ pub fn call<'a>( todo!() } - Instruction::GetField(source, field_index, destination) => { - // let object = load_value(...).unwrap_object(); - // let field_value = object.fields()[field_index]; - // put_value(..., destination, field_value.clone()); - todo!() + Instruction::GetFieldPointer(self_location, field_index, destination) => { + let object = load_value( + registers, + call_stack.top().stack(), + call_stack.top().fp(), + self_location, + ) + .unwrap_object() + .clone(); + let field_ref = ptr::from_ref(&object.borrow_mut().fields_mut()[*field_index]); + put_operand( + registers, + call_stack.top_mut(), + destination, + Operand::FieldPointer(field_ref), + ); + call_stack.top_mut().increment_ip(); } - Instruction::SetField(target, field_index, operand) => { - // let new_value = to_value(operand); - // let object = load_value(... target).unwrap_object(); - // object.fields_mut()[field_index] = new_value; - todo!() + Instruction::GetFieldPointerMut(self_location, field_index, destination) => { + let object = load_value( + registers, + call_stack.top().stack(), + call_stack.top().fp(), + self_location, + ) + .unwrap_object() + .clone(); + let field_ref = ptr::from_mut(&mut object.borrow_mut().fields_mut()[*field_index]); + put_operand( + registers, + call_stack.top_mut(), + destination, + Operand::FieldPointerMut(field_ref), + ); + call_stack.top_mut().increment_ip(); + } + + Instruction::ReadField(field_pointer_location, destination) => { + let field_pointer = load_operand( + registers, + call_stack.top().stack(), + call_stack.top().fp(), + field_pointer_location, + ) + .unwrap_field_pointer(); + // clone is very important, otherwise we mess up the self object! + let value = unsafe { field_pointer.read() }.clone(); + put_value(registers, call_stack.top_mut(), destination, value); + call_stack.top_mut().increment_ip(); + } + + Instruction::SetField(field_point_mut_location, operand) => { + let fp = call_stack.top().fp(); // borrow checker :) + let field_pointer_mut = load_operand_mut( + registers, + call_stack.top_mut().stack_mut(), + fp, + field_point_mut_location, + ) + .unwrap_field_pointer_mut(); + let value = set_field_operand_to_value( + operand, + registers, + call_stack.top(), + context.constants(), + ); + unsafe { + field_pointer_mut.write(value); + } + call_stack.top_mut().increment_ip(); } /* Add instructions */ @@ -442,27 +501,19 @@ pub fn call<'a>( Instruction::Pop(maybe_location) => { let value = call_stack.top_mut().stack_mut().pop().unwrap(); if let Some(location) = maybe_location { - put_value(registers, call_stack.top_mut(), location, value); + put_operand(registers, call_stack.top_mut(), location, value); } call_stack.top_mut().increment_ip(); } /* Return instructions */ Instruction::SetReturnValue(return_operand) => { - let value = match return_operand { - ReturnOperand::Location(location) => load_value( - registers, - call_stack.top().stack(), - call_stack.top().fp(), - location, - ) - .clone(), - ReturnOperand::Int(i) => Value::Int(*i), - ReturnOperand::Double(d) => Value::Double(*d), - ReturnOperand::String(constant_name) => { - load_constant_value(context.constants(), constant_name) - } - }; + let value = return_operand_to_value( + return_operand, + registers, + call_stack.top(), + context.constants(), + ); call_stack.top_mut().set_return_value(value); call_stack.top_mut().increment_ip(); } @@ -484,7 +535,7 @@ pub fn call<'a>( // push return value if some if let Some(return_value) = callee.take_return_value() { // n.b. callee - caller.stack_mut().push(return_value); + caller.stack_mut().push(Operand::Value(return_value)); } } else { // callee is the bottommost frame ("main" or whatever was called) diff --git a/dvm-lib/src/vm/operand.rs b/dvm-lib/src/vm/operand.rs new file mode 100644 index 0000000..bc0c72c --- /dev/null +++ b/dvm-lib/src/vm/operand.rs @@ -0,0 +1,51 @@ +use crate::vm::value::Value; + +#[derive(Debug)] +pub enum Operand { + Value(Value), + FieldPointer(*const Value), + FieldPointerMut(*mut Value), + Null, +} + +impl Operand { + pub fn unwrap_value(&self) -> &Value { + match self { + Operand::Value(value) => value, + _ => panic!("Attempt to unwrap {:?} as Value", self), + } + } + + pub fn unwrap_field_pointer(&self) -> *const Value { + match self { + Operand::FieldPointer(p) => *p, + _ => panic!("Attempt to unwrap {:?} as FieldPointer", self), + } + } + + pub fn unwrap_field_pointer_mut(&mut self) -> *mut Value { + match self { + Operand::FieldPointerMut(p) => *p, + _ => panic!("Attempt to unwrap {:?} as FieldPointerMut", self), + } + } +} + +impl Default for Operand { + fn default() -> Self { + Operand::Null + } +} + +impl Clone for Operand { + fn clone(&self) -> Self { + match self { + Operand::Value(value) => Operand::Value(Value::clone(value)), + Operand::FieldPointer(field_ref) => Operand::FieldPointer(*field_ref), + Operand::FieldPointerMut(_) => { + panic!("Cannot clone FieldRefMut") + } + Operand::Null => Operand::Null, + } + } +} diff --git a/dvm-lib/src/vm/operand_helpers.rs b/dvm-lib/src/vm/operand_helpers.rs new file mode 100644 index 0000000..e5883b5 --- /dev/null +++ b/dvm-lib/src/vm/operand_helpers.rs @@ -0,0 +1,140 @@ +use crate::instruction::{ + AddOperand, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SetFieldOperand, + SubtractOperand, +}; +use crate::vm::CallFrame; +use crate::vm::constant::Constant; +use crate::vm::operand::Operand; +use crate::vm::util::{load_constant_value, load_value}; +use crate::vm::value::Value; +use std::collections::HashMap; +use std::rc::Rc; + +pub fn move_operand_to_value( + move_operand: &MoveOperand, + registers: &[Operand], + current_frame: &CallFrame, + constants: &HashMap, Constant>, +) -> Value { + match move_operand { + MoveOperand::Location(location) => load_value( + registers, + current_frame.stack(), + current_frame.fp(), + location, + ), + MoveOperand::Int(i) => Value::Int(*i), + MoveOperand::Double(d) => Value::Double(*d), + MoveOperand::String(constant_name) => load_constant_value(constants, constant_name), + } +} + +pub fn push_operand_to_value( + push_operand: &PushOperand, + registers: &[Operand], + current_frame: &CallFrame, + constants: &HashMap, Constant>, +) -> Value { + match push_operand { + PushOperand::Location(location) => load_value( + registers, + current_frame.stack(), + current_frame.fp(), + location, + ), + PushOperand::Double(d) => Value::Double(*d), + PushOperand::Int(i) => Value::Int(*i), + PushOperand::String(constant_name) => load_constant_value(constants, constant_name), + } +} + +pub fn add_operand_to_value( + add_operand: &AddOperand, + registers: &[Operand], + current_frame: &CallFrame, + constants: &HashMap, Constant>, +) -> Value { + match add_operand { + AddOperand::Location(location) => load_value( + registers, + current_frame.stack(), + current_frame.fp(), + location, + ), + AddOperand::Int(i) => Value::Int(*i), + AddOperand::Double(d) => Value::Double(*d), + AddOperand::String(constant_name) => load_constant_value(constants, constant_name), + } +} + +pub fn subtract_operand_to_value( + subtract_operand: &SubtractOperand, + registers: &[Operand], + current_frame: &CallFrame, +) -> Value { + match subtract_operand { + SubtractOperand::Location(location) => load_value( + registers, + current_frame.stack(), + current_frame.fp(), + location, + ), + SubtractOperand::Int(i) => Value::Int(*i), + SubtractOperand::Double(d) => Value::Double(*d), + } +} + +pub fn multiply_operand_to_value( + multiply_operand: &MultiplyOperand, + registers: &[Operand], + current_frame: &CallFrame, +) -> Value { + match multiply_operand { + MultiplyOperand::Location(location) => load_value( + registers, + current_frame.stack(), + current_frame.fp(), + location, + ), + MultiplyOperand::Int(i) => Value::Int(*i), + MultiplyOperand::Double(d) => Value::Double(*d), + } +} + +pub fn return_operand_to_value( + return_operand: &ReturnOperand, + registers: &[Operand], + current_frame: &CallFrame, + constants: &HashMap, Constant>, +) -> Value { + match return_operand { + ReturnOperand::Location(location) => load_value( + registers, + current_frame.stack(), + current_frame.fp(), + location, + ), + ReturnOperand::Int(i) => Value::Int(*i), + ReturnOperand::Double(d) => Value::Double(*d), + ReturnOperand::String(constant_name) => load_constant_value(constants, constant_name), + } +} + +pub fn set_field_operand_to_value( + set_field_operand: &SetFieldOperand, + registers: &[Operand], + current_frame: &CallFrame, + constants: &HashMap, Constant>, +) -> Value { + match set_field_operand { + SetFieldOperand::Location(location) => load_value( + registers, + current_frame.stack(), + current_frame.fp(), + location, + ), + SetFieldOperand::Int(i) => Value::Int(*i), + SetFieldOperand::Double(d) => Value::Double(*d), + SetFieldOperand::String(constant_name) => load_constant_value(constants, constant_name), + } +} diff --git a/dvm-lib/src/vm/util.rs b/dvm-lib/src/vm/util.rs new file mode 100644 index 0000000..a16c5b3 --- /dev/null +++ b/dvm-lib/src/vm/util.rs @@ -0,0 +1,90 @@ +use crate::instruction::{ConstantName, Location}; +use crate::vm::CallFrame; +use crate::vm::constant::Constant; +use crate::vm::operand::Operand; +use crate::vm::value::Value; +use std::collections::HashMap; +use std::rc::Rc; + +#[inline] +fn calculate_from_offset(fp: usize, offset: isize) -> usize { + fp.checked_add_signed(offset).expect(&format!( + "Overflow when adding offset {} to fp {}", + offset, fp + )) +} + +pub fn load_operand<'a>( + registers: &'a [Operand], + stack: &'a [Operand], + fp: usize, + location: &Location, +) -> &'a Operand { + match location { + Location::Register(register) => ®isters[*register], + Location::StackFrameOffset(offset) => &stack[calculate_from_offset(fp, *offset)], + } +} + +pub fn load_operand_mut<'a>( + registers: &'a mut [Operand], + stack: &'a mut [Operand], + fp: usize, + location: &Location, +) -> &'a mut Operand { + match location { + Location::Register(register) => &mut registers[*register], + Location::StackFrameOffset(offset) => &mut stack[calculate_from_offset(fp, *offset)], + } +} + +pub fn load_value( + registers: &[Operand], + stack: &[Operand], + fp: usize, + location: &Location, +) -> Value { + load_operand(registers, stack, fp, location) + .unwrap_value() + .clone() +} + +pub fn load_constant_value( + constants: &HashMap, Constant>, + constant_name: &ConstantName, +) -> Value { + let constant = &constants[constant_name]; + match constant { + Constant::String(string_constant) => Value::String(string_constant.content_owned()), + } +} + +pub fn put_operand( + registers: &mut Vec, + current_frame: &mut CallFrame, + destination: &Location, + operand: Operand, +) { + match destination { + Location::Register(register) => { + registers[*register] = operand; + } + Location::StackFrameOffset(offset) => { + let fp = current_frame.fp(); + let target_index = fp.checked_add_signed(*offset).expect(&format!( + "Failed to calculate target index from fp + offset ({} + {})", + fp, offset + )); + current_frame.stack_mut()[target_index] = operand; + } + } +} + +pub fn put_value( + registers: &mut Vec, + current_frame: &mut CallFrame, + destination: &Location, + value: Value, +) { + put_operand(registers, current_frame, destination, Operand::Value(value)); +} diff --git a/dvm-lib/src/vm/value.rs b/dvm-lib/src/vm/value.rs index 70fda00..ecb68fe 100644 --- a/dvm-lib/src/vm/value.rs +++ b/dvm-lib/src/vm/value.rs @@ -1,4 +1,5 @@ use crate::vm::object::Object; +use std::cell::RefCell; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -38,11 +39,11 @@ impl Value { } } - pub fn unwrap_object(&self) -> &Object { + pub fn unwrap_object(&self) -> &Rc> { todo!() } - pub fn unwrap_object_mut(&mut self) -> &mut Object { + pub fn unwrap_object_mut(&mut self) -> &mut Rc> { todo!() } } diff --git a/dvm-lib/src/vm/value_util.rs b/dvm-lib/src/vm/value_util.rs deleted file mode 100644 index 25070da..0000000 --- a/dvm-lib/src/vm/value_util.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::instruction::{ConstantName, Location}; -use crate::vm::CallFrame; -use crate::vm::constant::Constant; -use crate::vm::value::Value; -use std::collections::HashMap; -use std::rc::Rc; - -pub fn load_value<'a>( - registers: &'a [Value], - stack: &'a [Value], - fp: usize, - location: &Location, -) -> &'a Value { - match location { - Location::Register(register) => ®isters[*register], - Location::StackFrameOffset(offset) => { - let value_index = fp.checked_add_signed(*offset).expect(&format!( - "Overflow when adding offset {} to fp {}", - *offset, fp - )); - &stack[value_index] - } - Location::RegisterField(register, field_index) => { - ®isters[*register].unwrap_object().fields()[*field_index] - } - Location::StackFrameOffsetField(offset, field_index) => { - let value_index = fp.checked_add_signed(*offset).expect(&format!( - "Overflow when adding offset {} to fp {}", - *offset, fp - )); - &stack[value_index].unwrap_object().fields()[*field_index] - } - } -} - -pub fn load_constant_value( - constants: &HashMap, Constant>, - constant_name: &ConstantName, -) -> Value { - let constant = &constants[constant_name]; - match constant { - Constant::String(string_constant) => Value::String(string_constant.content_owned()), - } -} - -pub fn put_value( - registers: &mut Vec, - current_frame: &mut CallFrame, - destination: &Location, - value: Value, -) { - match destination { - Location::Register(register) => { - registers[*register] = value; - } - Location::StackFrameOffset(offset) => { - let fp = current_frame.fp(); - let target_index = fp.checked_add_signed(*offset).expect(&format!( - "Failed to calculate target index from fp + offset ({} + {})", - fp, offset - )); - current_frame.stack_mut()[target_index] = value; - } - Location::RegisterField(register, field_index) => { - registers[*register].unwrap_object_mut().fields_mut()[*field_index] = value; - } - Location::StackFrameOffsetField(offset, field_index) => { - let fp = current_frame.fp(); - let target_index = fp.checked_add_signed(*offset).expect(&format!( - "Failed to calculate target index from fp + offset ({} + {})", - fp, offset - )); - current_frame.stack_mut()[target_index] - .unwrap_object_mut() - .fields_mut()[*field_index] = value; - } - } -} diff --git a/e2e-tests/src/lib.rs b/e2e-tests/src/lib.rs index 3f8e45b..3e2a765 100644 --- a/e2e-tests/src/lib.rs +++ b/e2e-tests/src/lib.rs @@ -6,6 +6,7 @@ mod e2e_tests { use dmc_lib::symbol_table::SymbolTable; use dvm_lib::vm::constant::{Constant, StringConstant}; use dvm_lib::vm::function::Function; + use dvm_lib::vm::operand::Operand; use dvm_lib::vm::value::Value; use dvm_lib::vm::{CallStack, DvmContext, call}; use std::rc::Rc; @@ -90,7 +91,7 @@ mod e2e_tests { function_name: &str, arguments: &[Value], ) -> Option { - let mut registers: Vec = vec![Value::Null; REGISTER_COUNT]; + let mut registers: Vec = vec![Operand::Null; REGISTER_COUNT]; let mut call_stack = CallStack::new(); call(