Du befindest dich hier: FSI Informatik » Prüfungsfragen und Altklausuren » Hauptstudiumsprüfungen » Lehrstuhl 2 » Allgemein
Inhaltsverzeichnis
Allgemein
An sich ganz entspannt. Ich hab mich an einer Stelle (Kosarajus) ziemlich verrannt und wusste keine Details mehr, bei der Frage mit „warum zwei Stacks im Interpreter“ wusste ich nicht genau was gemeint ist. Hat sich aber augenscheinlich nicht negativ aufs Ergebnis ausgewirkt.
Blockpraktikum/JIT
F: Was haben wir im Blockpraktikum gemacht?
A: Bytecode Interpreter, JIT nur mit Stack, JIT mit Registern, Inlining
F: Warum interpretieren nicht auf E2 AST?
A: Langsamer, da Baum ablaufen und direktes Übersetzen nach Native für JIT>=1 wäre schwieriger.
F: Wie funktioniert interpretieren?
A: Bytecode Instruktion dekodieren, switch case auf Opcode, abarbeiten, PC anpassen, rinse and repeat. Kann man dann noch schneller machen mit indirektem durchfädeln
F: Wie funktionieren Funktionsaufrufe?
A: Rekursion im Systemstack
F: Und die Argumente?
A: Über Interpreterstack
F: Könnte man hier noch was optimieren/Wieso braucht man zwei Stacks?
A: Ehm….Lokalität?
F: Was als nächstes
A: JIT1, ganze Funktion auf einmal nach native kompilieren. Bei Funktionsaufrufen muss man aufpassen, die Zielfunktion ist eventuell noch nicht kompiliert. Deshalb einen Sprung ins Trampolin einkompilieren. Wenn die Funktion schon kompiliert ist, kann man direkt den Sprung einkompilieren, das macht nachpatchen aber schwierig (falls neu kompiliert). Deshalb if (f→native_code) in native einkompilieren.
F: Dann sagtest du Registervergabe, wie geht das?
A: Idee vom linear Scan. Angenäherte Lebensspannen vom ersten Schreiben bis letztes Lesen ohne Löcher. Bei Schleifen muss man aufpassen, da die Textreihenfolge dann nicht mit der Lebensspanne übereinstimmt. Deshalb alle Instruktionen einer Schleife zusammenfassen in starken Zusammenhangskomponenten.
F: Wie berechnet man die starken ZHK für diesen Graph? (Blatt gegeben)
A: Kosarajus Algorithmus, Tiefensuche in beide Richtungen. Erste Tiefensuche auf Beispiel-KFG kurz gemacht. Zweiten Schritt wusste ich nicht mehr genau
Linker&Lader
F: Sagen wir e2c kompiliert jetzt C, was muss man beachten?
A: C Programme bestehen aus C Dateien die dann in einzelen Objektdateien kompiliert werden. Die muss man vor dem Ausführen/Verwenden als Bibliothek noch zusammenbinden
F: Was heißt das?
A: Jedes Modul kann ja Funktionen der anderen Module verwenden. z.B ein Print Modul mit print Funktion und ein Main Modul. Im Main Modul steht erstmal nur eine Referenz auf das print *Symbol*, das wird durch den Binder aufgelöst, entweder beim kompilieren oder später zur Laufzeit
F: Wie funktioniert das auflösen und was braucht man da für Daten?
A: Symboltabelle (Einwurf: eigentlich Relokationstabelle) enthält enthält Informationen zu Symbolen die Relokationen brauchen (Typ also Absolut, GOT Relativ…, den Namen und das Offset im Binary)
F: Wie ist das mit Bibliotheken?
A: Es gibt unshared Bibliotheken (.a Dateien), sind doof weil man bei Änderungen in der Bibliothek alle Executables neu linken muss. Deshalb lieber shared Bibliotheken. Da gibt es dann statische und dynamische shared Bibliotheken. Statische shared Bibliotheken haben ne feste Adresse, macht bessere Performanz, wenn man Änderungen an der Bibliothek möglich machen will braucht man ne Indirektionstabelle. Dynamische shared Bibliotheken brauchen PIC, mit RIP relative oder GOT/PLT Indirektion.
Exceptions
F: Was muss man für Exceptions beachten?
A: Man muss sie implementieren und später im Compiler beachten. Implementieren z.B mit Stack Cutting oder Stack Unwinding. Stack Cutting: also wie wenn man in C Longjumps bei nem Fehler macht. Ziel des Longjumps ist dann der Exceptionhandler.
F: Wie funktioniert das?
A: In dem Jumpbuf stehen Kontextinformationen (Stackpointer, PC)
F: Nachteile davon?
A: Man bezahlt jedes Mal Kosten für die Exception da man den Jumpbuf allozieren und befüllen muss.
F: Muss man allozieren?
A: Gut man könnte die auch statisch allozieren da die Exceptionhandler statisch bekannt sind. Befüllen muss man trotzdem immer
F: Wie implementiert man unterschiedliche Exceptiontypen?
A: Vorlesung stellte Verfahren mit verketteter Liste vor Bei Exception die Elemente dieser Liste ablaufen
F: Was bedeuten die Elemente der Liste?
A: Entsprechen einzelnen Catchblöcken
F: Wie kann man Zusatzkosten von Stack Cutting vermeiden?
A: Stack Unwinding, da bezahlt man keine Kosten
F: Keine Kosten?
A: Immer noch Zusatzkosten aber nur ein Jump am Ende des try Blocks. An der Stelle hab ich auf einem Blatt Papier das Übersetzungsschema mit den 4 Labels aufgemalt. Es gibt dann pro Funktion eine Tabelle mit Intervallen, Exceptiontyp und Handlerlabel
F: Wie funktioniert nested Try Catch, was muss man da beachten
A: Tabelle sortieren, „spezifischster“ Handler zuerst
F: Was muss man später noch beachten
A: Der Kontrollflussgraph explodiert, deshalb faktorisierter KFG. Hier muss man in der Datenflussanalyse beachten, potentially throwing instructions bei den GEN und KILL Mengen beachten.