====== Ausgewählte Kapitel aus dem Übersetzerbau ====== ===== Allgemein ===== Angenehme Atmosphäre. Wie üblich stehen Papier und Stift bereit. Erster Teil der Prüfung geht über das Praktikum. Es wird (zumindest bei mir) alles vom ersten und letzten Tag gefragt, warum man was gemacht hat, worauf man geachtet hat, und potentiell auch warum die Implementierung kaputt geht wenn man xyz nicht beachtet. Das ist sehr angenehm, insbesondere wenn man verstanden hat, was man da die letzte Woche etwa 50 Stunden lang gemacht hat ;) ===== Prüfungsverlauf ===== ==== Praktikum ==== **F:** Was haben wir im Praktikum gemacht? * Lader fuer TVM, dann Interpreter und JIT, der Tag fuer Tag optimiert wurde. **F:** Wie funktioniert ein Interpreter? * switch/case über Opcodes * Ausführung des Befehls in Funktion * Rücksprung * Erneute Ausführung **F:** Vor und Nachteile? * Einfach zu schreiben (ein Nachmittag), schneller Start, wenig Speicherverbrauch * Cachedruck durch Datencache, Wiederholung, viele Spruenge. **F:** Wie kann man es besser machen? * Indirekt durchgefädelte Interpretation * Instruktionsroutinen springen nicht zurück, sondern springen nächste Instruktion direkt an **F:** Noch bessere Variante? * Direkt durchgefädelte/vorübersetzte Interpretation * Die dann erklaeren. **F:** Was macht JIT1? * Einfachen Maschinencode erzeugen (keine Optimierungen) * "Instruktionslokale Registervergabe" * Trampolinfunktion **F:** Was braucht die Trampolinfunktion alles? * Ist aufgerufene Funktion schon kompiliert? Soll sie interpretiert werden? * Aufruf der Funktion mit richtigen Parametern * Rückgabe des von der aufgerufenen Funktion zurückgegebenen Returnwertes * Zentrale Stelle fuer Optimierungsentscheidungen **F:** Was, wenn man nun in einer While(true)-Schleife steckt, die interpretiert wird, kann man die dann Optimieren weil die laueft ja dann ewig? * On Stack Replacement * Erklaeren wie (Methodenschachtel runter, konzeptionelle Methodenschachtel, potentiell Optimieren und in den Stack **F:** Hu, hoert sich kompliziert an, alles Rueckgaengig zu machen und die konzeptionelle Schachtel fuer alle Programmcounter usw zu bauen, das dann alles richtig zu machen * Nur an bestimmten Stellen (Methodenanfang, Schleifenruecksprung) Replacement erlauben. **F:** Was macht JIT2? * Registervergabe (aber nicht nach Graphfärben, um Zeit zu sparen) * Linear Scan * Lebendigkeitsintervalle auf ZHKs aufbauen * ZHKs sind topologisch sortiert * Registervergabe wie in VL * Heuristiken zum Spillen **F:** Verbesserungen? * Lebensspannen aufteilen, falls Löcher * U.U. mehr freie Register **F:** Verbesserungen? * Spillcode erzeugen, wenn Register gebraucht wird statt komplett in Speicher auszulagern (vergleiche auch Bin-Packing) **F:** Was macht JIT3? * Inlining * Welche Jumps wie anzupassen sind (vor geinlinter, in geinlinter, nach geinlinter Funktion, returns, calls, Offsets) ==== Linker und Lader ==== **F:** Statische Shared Librarys, wie funktionieren die, welche Vor- und Nachteile gibts da? * Jede Bibliothek hat feste Position * Keine Relokation spaeter notwendig, Linker hat alles erledigt, Lader muss nichts rel * Aber: Zentrale Adressvergabe notwendig, keine Librarys duerfen sich ueberlappen da potentiell jede Library mit jeder anderen kobinierbar sein soll! **F:** Es gibt da auch noch so eine Tabelle... * Gemeint war hier die Indirektions-Sprungtabelle, falls sich die Library aendert, dass man nicht immer das Programm neu binden muss, nur weil sich Offsets aendern **F:** Wenn man nun groessere API-Aenderungen hat, muss man dann neu Binden? * Hab nach etwas Ueberlegung "Ja" gesagt, wenn sich Funktionen in Parametern aendern oder nicht mehr vorhanden sind oder anders heissen, scheint richtig gewesen zu sein. ==== Watermarking ==== **F:** Was ist der Unterschied zwischen statischem und dynamischen Verfahren? * Statische sichtbar ohne dass Code ausgefuehrt wird * Dynamisch muss ausgefuehrt werden (bsp mit ungewoehnlichen eingaben) um bestimmtes Verhalten zu triggern **F:** Kannst du jeweils Beispiele nennen? * Statisch: Basierend auf Permutation Variablendeklarationen drehen, Basisbloecke drehen * Dynamisch: Besonderes Threadscheduling hervorrufen **F:** Was ist das Problem insbesondere an statischen Verfahren? * Der Compiler zerstoert beim Optimieren viele Techniken (Basisbloecke drehen beispielsweise ist danach wahrscheinlich hinueber...) ==== Funktionale Sprachen ==== **F:** Wir wollen nun E3 schreiben, dass Funktional ist. Was muss man hierbei beachten? * Sehr offene Fragen, hier kann man quasi das antworten, worauf man Lust hat (glaube ich) * Hab zuerst Typinterferenz erklaert mit einem kleinen Beispiel, hier ist vorallem das Stichwort "Unifikation" wichtig gewesen, hab das dann am Beispiel auch gezeigt * Danach wurde nach PAP gefragt, dass man Closures braucht, die auf dem Heap liegen, und warum man die braucht. ==== Exceptions ==== **F:** Worauf achtet man bei der Uebersetzung von Exceptions besonders? * Exceptions sind Ausnahmen, es ist wichtiger die Laufzeit im normalen Programm zu minimieren als im Fall der Ausnahme, da diese wahrscheinlich nur selten auftreten **F:** Welche Varianten haben wir kennengelernt, um Ausnahmen zu uebersetzen? * Stack Cutting und Stack Unwinding * Jeweils mit Vor- und Nachteilen erklaert. **F:** Letzte Frage, warum brauchen wir angepasste Datenflussanalysen fuer den Faktorisierten Kontrollflussgraphen? * Hier hab ich ein kleines Beispiel aufgemalt mit Konstantenfortschreibung, dass der Wert als Konstant angenommen wird, aber die Exception-Kante eigentlich in der Mitte des Blocks ist und somit auch vorherige Werte noch erreichbar sind.