Kapitel 7 - Virtuelle Maschine

Gegenstand dieses Kapitels ist die virtuelle Maschine (VM) der Hack-Architektur, die wir im Detail studieren. Sie dient als Zwischenschicht zwischen der Hochsprache Jack und dem Hack-Assembler, und bietet gegenüber dem Assembler einigen Mehrwert, der die Übersetzung aus einer Hochsprache erleichtert. Dafür arbeitet die VM mit einer rudimentären Speicherverwaltung, die den Arbeitsspeicher in verschiedene Segmente aufteilt. Dies ermöglicht die Aufteilung in logische Bereiche, wie statische und lokale Variablen oder Objekte und Arrays auf dem Heap. Des weiteren wird Funktionalität zur Verwaltung von Funktionsaufrufen zur Verfügung gestellt.

Inhalt

Abschnitt 1 - Funktion der virtuellen Maschinen

Folien 1-14

Wir starten mit einer allgemeinen Einführung in die Idee der virtuellen Maschinen (VMs), unterscheiden prozeßbasierte von systembasierten VMs, und diskutieren Vor- und Nachteile. Für die Vorlesung ist vor allem die Verwendung der VM als Zwischenschicht zwischen Hochsprache und eigentlichen System interessant, die VM der Hack-Architektur ist eine typische prozeßbasierte VM. Das Ziel der Übersetzung aus Hochsprachen definiert die Hauptaufgaben dieser Klasse von VM, insbesondere müssen effiziente Möglichkeiten zur Speicherorganisation zur Verfügung gestellt werden. Wir verschaffen uns einen ersten Überblick über die konkrete Speicherorganisation der Hack-VM in verschiedene Speichersegmenten.


Index

00:00 Einleitung und Übersicht des Kapitels
02:10 Hochsprachen und Übersetzung, Idee der virtuellen Maschine
09:20 System- und prozessbasierte virtuelle Maschinen
14:00 Vor- und Nachteile der virtuellen Maschinen
18:10 Übersetzungspfad, Notwendigkeit der Speicherorganisation
21:50 Erste Übersicht der Speichersegmente der Hack-VM
25:50 Ausblick auf die folgenden Abschnitte


Abschnitt 2 - Stapelarithmetik und Speicheraufteilung

Folien 15-27

Wir studieren den Aufbau der VM in der Hack-Architektur. Eine zentrale Aufgabe innerhalb eines Programms ist das Auswerten von Ausdrücken, wofür der Stapelspeicher als Datenstruktur zur Verfügung gestellt wird. Daten können aus verschiedenen Speichersegmenten auf den Stapel geschrieben werden und umgekehrt. Die VM muß den Speicher des Hack-Systems geeignet aufteilen, um die Semantik einer höheren Programmiersprache effizient umsetzen zu können. Wir schauen diese Aufteilung im Detail an, welche Segmente es gibt, wo sie liegen, und wie man sie innerhalb von Programmen der VM anspricht.


Index

00:00 Die VM des Hack-Systems
03:15 Der Stapel als zentrale Datenstruktur
05:45 Stapelarithmetik: Rechnen mit Hilfe des Stapels
10:15 Arithmetisch-logische Funktionen der VM
13:28 Beispiel für die Auswertung eines arithmetischen Ausdrucks
19:20 Beispiel für die Auswertung eines logischen Ausdrucks
21:50 Speicherzugriff, Ersetzen der Variablennamen durch Segment und Index
24:30 Speicheraufteilung der Hack-VM 1: virtuelle Register
31:30 Speicheraufteilung der Hack-VM 2: statische Variablen und Stack
38:40 Speicheraufteilung der Hack-VM 3: heap und memory-mapped I/O
40:16 Abbildung der Speichersegmente 1: local, argument, this, that
45:00 Abbildung der Speichersegmente 2: pointer, temp
48:35 Abbildung der Speichersegmente 3: static, constant
50:30 Zusammenfassung


Abschnitt 3 - Programmablaufsteuerung, Objekt- und Arraybehandlung

Folien 27-32

Wir betrachten kurz, wie die Programmablaufsteuerung der VM funktioniert, die mit Hilfe von symbolischen Sprungzielen (Labeln) und bedingten, bzw. unbedingten Spunganweisungen realisiert wird. Bedingte Sprünge prüfen dabei das oberste Element auf dem Stapel. Wir lernen an einem kurzen Beispiel auch schon einmal ein paar Konventionen für den Aufruf von Unterprogrammen kennen. Anschließend vertiefen wir unsere Kenntnisse über die Speichersegmente, indem wir die Übersetzung ausgewählter push- und pop-Anweisungen in die Maschinensprache studieren. Schließlich schauen wir uns noch an, wie Objekte und Arrays der Hochsprache mit Hilfe der this- und that-Segmente behandelt werden können, welche die VM zur Verfügung stellt.


Index

00:00 Einleitung
01:44 Programmablaufsteuerung in Programmen der VM: Label und Sprunganweisungen
04:40 Beispiel: Übersetzung einer If-Anweisung
07:17 Beispiel: Implementation einer Funktion und Konventionen für den Stack
15:00 Anzahl lokale Variablen bei Deklaration einer Funktion vs. Anzahl Argumente bei Aufruf
16:50 Beispiele für die Übersetzung von VM-Anweisungen in Assembler: push constant n
22:00 - an diesem Beispiel: Optimierung von Assemblerprogrammen
24:30 Beispiele für die Übersetzung von VM-Anweisungen in Assembler: pop local n
32:40 Beispiele für die Übersetzung von VM-Anweisungen in Assembler: push argument n
36:10 Objektbehandlung mit Hilfe des this-Segments
42:00 Beíspiel: Setzen des this-Segments und einer Objekteigenschaft
44:30 Beispiele für die Übersetzung von VM-Anweisungen in Assembler: pop pointer 0
46:50 Arraybehandlung mit Hilfe des that-Segments
49:20 Beispiel: Setzen eines Array-Elements mit variablem Index

Errate

29:45 In dieser Zeile natürlich D=A statt D=n (was ja gar nicht direkt geht).


Abschnitt 4 - Funktionsaufrufe, VM-Simulation

Folien 34-56

Als letzte wesentliche Aufgabe der VM Betrachten wir die Funktionsaufrufe und die zugehörigen VM-Befehle, insbesondere wie sie implementiert und in Assembler realisiert werden können. Bei Aufruf der Funktion muß die Arbeitsumgebung sowie Rücksprungadresse der Funktion auf dem Stack abgelegt werden, sowie die neuen Segmente ARG und LCL für aufgerufene Funktion angelegt werden - ersteres geschieht beim call, letzteres beim Eintritt in die Funktion. Beim Rücksprung müssen die gesicherten Segmentadressen dann wiederhergestellt werden. Diese Arbeitsumgebung einer Funktion nennt sich der stack frame oder Rahmen, und die VM übernimmt den wesentlichen Teil der fehleranfälligen Verwaltungsarbeit. Zum Abschluß gibt es noch einen Überblick über den fertigen Befehlssatz der VM, sowie einige Bemerkungen zur Hack-Architektur und der Emulationsumgebung.


Index

00:00 Einleitung: Konventionen für Funktionsaufrufe in der VM, Aufgaben der Implementation
06:15 Sprachelemente für Aufruf und Definition von Funktionen
08:50 Übersetzungspfad und Speichersegmente, Konsequenzen für den Ablauf des Funktionsaufrufs
13:00 Speicherverwaltung beim Aufruf einer Funktion, Rahmen der Funktion (stack frame)
19:00 Beispiel: Funktionsaufrufe in mehreren Ebenen
20:50 Implementation des call-Befehls der VM, Sichern der Segmente, Umsetzung in Assembler
26:30 Implementation der Funktionsdeklaration, Anlegen der lokalen Variablen
30:30 Implementation des return-Befehls, Aufräumen des Speichers und Wiederherstellung der Segmentadressen
33:25 Beispiel: Stack-Frames beim Funktionsaufruf in mehreren Ebenene
37:05 Zusammenfassung: Befehlssatz der VM, Bemerkungen, Programmstart
42:45 VM-Emulator im Softwarepaket zur Hack-Architektur, Vergleich mit Java
46:40 Fazit des Kapitels und Ausblick