package de.fuberlin.projectF.CodeGenerator; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.fuberlin.projectF.CodeGenerator.model.Array; import de.fuberlin.projectF.CodeGenerator.model.ArrayPointer; import de.fuberlin.projectF.CodeGenerator.model.MMXRegisterAddress; import de.fuberlin.projectF.CodeGenerator.model.Record; import de.fuberlin.projectF.CodeGenerator.model.RecordPointer; import de.fuberlin.projectF.CodeGenerator.model.Reference; import de.fuberlin.projectF.CodeGenerator.model.RegisterAddress; import de.fuberlin.projectF.CodeGenerator.model.StackAddress; import de.fuberlin.projectF.CodeGenerator.model.Variable; /* Class: MemoryContext * Diese Klasse verwaltet die Register- und Stackbelegungen * eines bestimmten Kontext's, sprich einer Funktion. */ public class MemoryContext { private String name; private int stackPointer; private HashMap<String, Reference> references; private HashMap<String, Variable> variables; private HashMap<String, Array> arrays; private HashMap<String, Record> records; private HashMap<String, ArrayPointer> arrayPtrs; private HashMap<String, RecordPointer> recordPtrs; private ArrayList<RegisterAddress> registers; private ArrayList<RegisterAddress> freeRegisters; private HashMap<RegisterAddress, Reference> usedRegisters; private ArrayList<MMXRegisterAddress> mmxRegisters; private ArrayList<MMXRegisterAddress> freeMMXRegisters; private HashMap<MMXRegisterAddress, Variable> usedMMXRegisters; //Konstruktor der Klasse: initialisieren aller benötigten Variablen public MemoryContext(String name) { this.name = name; stackPointer = 0; references = new HashMap<String, Reference>(); variables = new HashMap<String, Variable>(); arrays = new HashMap<String, Array>(); records = new HashMap<String, Record>(); arrayPtrs = new HashMap<String, ArrayPointer>(); recordPtrs = new HashMap<String, RecordPointer>(); registers = new ArrayList<RegisterAddress>(); freeRegisters = new ArrayList<RegisterAddress>(); usedRegisters = new HashMap<RegisterAddress, Reference>(); mmxRegisters = new ArrayList<MMXRegisterAddress>(); freeMMXRegisters = new ArrayList<MMXRegisterAddress>(); usedMMXRegisters = new HashMap<MMXRegisterAddress, Variable>(); //Zur Verfügung stehende Register erstellen for (int i = 0; i < 6; i++) { RegisterAddress r = new RegisterAddress(i); registers.add(r); freeRegisters.add(r); } for (int i = 0; i < 8; i++) { MMXRegisterAddress mr = new MMXRegisterAddress(i); freeMMXRegisters.add(mr); mmxRegisters.add(mr); } } //liefert den Namen des Kontexte's public String getName() { return name; } // Vorhandene MMX Registervariable hinzufügen, z. B. um Rückgabewert zu // speichern public void addMMXRegVar(String name, String type, MMXRegisterAddress reg) { Variable var = new Variable(name, type, reg); put(var); freeMMXRegisters.remove(reg); usedMMXRegisters.put(reg, var); } // Vorhandene Registervariable hinzufügen, z. B. um Rückgabewert zu // speichern public void addRegVar(String name, String type, RegisterAddress reg) { Variable var = new Variable(name, type, reg); put(var); freeRegisters.remove(reg); usedRegisters.put(reg, var); } // Vorhandene Stackvariable hinzufügen, z. B. Funktionsparameter, nach // Aufruf public void addStackVar(String name, String type, int stackAddress) { Variable newVar = new Variable(name, type, stackAddress); put(newVar); } //erstellt einen ArrayPointer, der auf einen anderen ArrayPointer aufbaut, //also z.b. bei mehrdimensionalen Arrays public ArrayPointer contArrayPtr(String name, String lastPtr, String offset, String values) { int value = 1; values = values.substring(values.indexOf('x'), values.lastIndexOf('x')); Pattern p = Pattern.compile("\\d+"); Matcher m = p.matcher(values); while (m.find()) { value *= new Integer(m.group(0)); } ArrayPointer oldPtr = arrayPtrs.get(lastPtr); ArrayPointer arrPtr = new ArrayPointer(name, oldPtr, value); put(arrPtr); return arrPtr; } //markiert ein MMX Register als überschreibbar public void freeMMXRegister(MMXRegisterAddress tmp) { usedMMXRegisters.remove(tmp); freeMMXRegisters.add(tmp); } //markiert ein Register als überschreibbar public void freeRegister(RegisterAddress reg) { usedRegisters.remove(reg); freeRegisters.add(reg); } // public Reference get(String name) { return references.get(name); } //liefert ein freies "überschreibbares" MMX Register public MMXRegisterAddress getFreeMMXRegister() { try { return freeMMXRegisters.remove(0); } catch (IndexOutOfBoundsException e) { return null; } } //liefert ein freies "überschreibbares" Register public RegisterAddress getFreeRegister() { try { RegisterAddress r = freeRegisters.remove(0); return r; } catch (IndexOutOfBoundsException e) { return null; } } //liefert ein definiertes Register mit dem index i public RegisterAddress getRegister(int i) { return registers.get(i); } //liefert eine Liste aller Variablen die sich in einem MMX Register befinden public List<Variable> getMMXRegVariables() { ArrayList<Variable> vars = new ArrayList<Variable>(variables.values()); for (Variable v : variables.values()) { if (v.onStack() || v.inReg()) vars.remove(v); } return vars; } //liefert eine Liste aller Variablen die sich in einem Register befinden public List<Variable> getRegVariables() { ArrayList<Variable> vars = new ArrayList<Variable>(variables.values()); for (Variable v : variables.values()) { if (v.onStack() || v.inMMXReg()) vars.remove(v); } return vars; } //prüft ob eine Variable in einem MMX Register ist public boolean inMMXReg(String name) { if (variables.containsKey(name)) return variables.get(name).inMMXReg(); return false; } //prüft ob eine Variable in einem Register ist public boolean inReg(String name, int regNumber) { if (variables.containsKey(name)) return variables.get(name).inReg(regNumber); return false; } //verschiebt eine Variable aus einem MMX Register auf den Stack public void MMXRegToStack(Variable var) { stackPointer -= var.getSize(); MMXRegisterAddress reg = var.getMMXRegAddress(); freeMMXRegisters.add(reg); usedMMXRegisters.remove(reg); var.addStackAddress(new StackAddress(stackPointer)); } //erstellt ein neues Array public Array newArray(String name, String type, int length) { Array newArr = new Array(name, type, length, stackPointer); stackPointer -= newArr.getSize(); put(newArr); return newArr; } //erstellt ein neuen Record public Record newRecord(Record rec) { rec.setAddress(stackPointer); put(rec); return rec; } //erstellt einen ArrayPointer der auf inhalte in einem Array zeigt public ArrayPointer newArrayPtr(String name, String arrayName, String values, RegisterAddress reg) { Array arr = arrays.get(arrayName); int value = arr.getLength() / new Integer(values.split(" ")[1]); ArrayPointer arrPtr = new ArrayPointer(name, arr, value, reg); stackPointer -= arrPtr.getSize(); put(arrPtr); freeRegisters.remove(reg); usedRegisters.put(reg, arrPtr); return arrPtr; } //erstellt einen RecordPointer der auf interne variablen in einem Record zeigt public RecordPointer newRecordPtr(String name, String rec, String offset) { RecordPointer tmp; if (isRecordPtr(rec)) tmp = new RecordPointer(name, recordPtrs.get(rec), new Integer( offset)); else tmp = new RecordPointer(name, records.get(rec), new Integer(offset)); put(tmp); return tmp; } //erstellt Referenzen zu anderen Variablen, z.B. das %4 und %3 auf die selbe Variable zeigen public void newReference(String name, String var) { references.put(name, references.get(var)); } //erstellt eine neue Variable auf dem Stack public Variable newStackVar(String name, String type) { Variable newVar = new Variable(name, type, stackPointer); stackPointer -= newVar.getSize(); put(newVar); return newVar; } //prüft ob eine Variable auf dem Stack liegt public boolean onStack(String name) { if (references.containsKey(name)) return references.get(name).onStack(); return false; } //fügt ein Array zu den Referenzen hinzu private void put(Array arr) { String name = arr.getName(); arrays.put(name, arr); references.put(name, arr); } //fügt ein Record zu den Referenzen hinzu private void put(Record rec) { String name = rec.getName(); records.put(name, rec); references.put(name, rec); } //fügt ein ArrayPointer zu den Referenzen hinzu private void put(ArrayPointer arrPtr) { String name = arrPtr.getName(); arrayPtrs.put(name, arrPtr); references.put(name, arrPtr); } //fügt ein RecordPointer zu den Referenzen hinzu private void put(RecordPointer recPtr) { String name = recPtr.getName(); recordPtrs.put(name, recPtr); references.put(name, recPtr); } //fügt eine Variable zu den Referenzen hinzu private void put(Variable var) { String name = var.getName(); variables.put(name, var); references.put(name, var); } //verschiebt eine Variable aus einem Register auf den Stack public StackAddress regToStack(Variable var) { stackPointer -= var.getSize(); RegisterAddress reg = var.getRegAddress(); StackAddress movedTo = new StackAddress(stackPointer); var.addStackAddress(movedTo); var.freeRegister(reg); freeRegister(reg); return movedTo; } //verschiebt eine Variable aus einem MMX Register auf den Stack public StackAddress mmxRegToStack(Variable var) { stackPointer -= var.getSize(); MMXRegisterAddress reg = var.getMMXRegAddress(); StackAddress movedTo = new StackAddress(stackPointer); var.addStackAddress(movedTo); var.freeMMXRegister(reg); freeMMXRegister(reg); return movedTo; } //liefert ein Array mit dem Namen <name> public Array getArray(String name) { return arrays.get(name); } //prüft ob <name> ein RecordPointer ist public boolean isRecordPtr(String name) { return recordPtrs.containsKey(name); } //liefert einen vorhandenen RecordPointer mit dem Namen <name> public RecordPointer getRecordPtr(String name) { return recordPtrs.get(name); } //liefert eine Liste von Registern die derzeit nicht überschreibbar sind public HashMap<RegisterAddress, Reference> getUsedRegisters() { return usedRegisters; } //liefert eine Liste von MMX Registern die derzeit nicht überschreibbar sind public HashMap<MMXRegisterAddress, Variable> getUsedMMXRegisters() { return usedMMXRegisters; } //liefert ein definiertes MMX Register public MMXRegisterAddress getMMXRegister(int i) { return mmxRegisters.get(i); } //prüft ob ein Register überschreibbar ist public boolean isFree(int i) { return freeRegisters.contains(registers.get(i)); } public void freeArrayPointer(String target) { if (arrayPtrs.containsKey(target)) freeRegister(arrayPtrs.get(target).getRegAddress()); } }