use crate::constants_table::ConstantsTable; 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::VrUser; use crate::ir::util::propagate_spills; use crate::offset_counter::OffsetCounter; 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 IrAssign { destination: Rc>, initializer: Box, } impl IrAssign { pub fn new(destination: Rc>, initializer: IrOperation) -> Self { Self { destination, initializer: initializer.into(), } } } impl VrUser for IrAssign { fn vr_definitions(&self) -> HashSet { self.destination .borrow() .descriptor() .vr_variable_descriptors() } fn vr_uses(&self) -> HashSet { self.initializer.vr_uses() } fn propagate_spills(&mut self, spills: &HashSet) { propagate_spills(&mut self.destination, spills); } fn propagate_register_assignments( &mut self, assignments: &HashMap, ) { let mut borrowed_destination = self.destination.borrow_mut(); if let IrVariableDescriptor::VirtualRegister(vr_variable) = borrowed_destination.descriptor_mut() { if assignments.contains_key(vr_variable) { vr_variable.set_assigned_register(assignments[vr_variable]); } } } fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) { let mut borrowed_destination = self.destination.borrow_mut(); if let IrVariableDescriptor::Stack(stack_variable) = borrowed_destination.descriptor_mut() { stack_variable.use_next_offset(counter); } } } impl Assemble for IrAssign { fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) { 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_parameter_or_variable().as_location(); builder.push(Instruction::GetFieldPointer( self_location, ir_get_field_ref.field_index(), destination, )); } IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => { let self_location = ir_get_field_ref_mut .self_parameter_or_variable() .as_location(); builder.push(Instruction::GetFieldPointerMut( self_location, ir_get_field_ref_mut.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)); } IrOperation::Binary(ir_binary_operation) => { ir_binary_operation.assemble_assign(builder, constants_table, destination); } IrOperation::Call(ir_call) => { ir_call.assemble(builder, constants_table); builder.push(Instruction::Pop(Some(destination))); } IrOperation::Allocate(ir_allocate) => builder.push(Instruction::Allocate( ir_allocate.class_fqn_owned(), destination, )), } } } impl Display for IrAssign { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, "{}: {} = {}", self.destination.borrow(), self.destination.borrow().type_info(), self.initializer ) } }