next up previous contents
Next: Zusammenfassung Up: Deoptimierung Previous: On-Stack Replacement   Inhalt

Ausnahmebehandlung

Das Umordnen von Programmstücken ist ein wichtiges Verfahren zur Optimierung. Durch die Forderung nach präziser Ausnahmebehandlung (s. Abschnitt 2.1.2) im Zusammenhang mit vielen laufzeitgeprüften Operationen verhindert die Java-Spezifikation diese Option. Akzeptiert man jedoch für den Ausnahmefall eine langsamere Ausführung, gewinnt man einen Teil der möglichen Optimierungen zurück. Der hier vorgestellte Algorithmus geht auf [Gupta et al., 2000] zurück.

Abbildung 3.4: Laufzeittests
\scalebox{0.7}{\includegraphics{execution/util/exception-1}}

Die Grundidee ist dabei die folgende: die betroffenen Operationen (beispielsweise getfield p.x) werden für die interne Compiler-Repräsentation aufgeschlüsselt. Sie bestehen aus drei Teilen (siehe Abbildung 3.4): ein Teil prüft, ob die Ausnahmebedingung vorliegt (p == null), einer besteht aus der Ausnahme selbst (throw new NullPointerException()) und einer aus dem eigentlichen Kern der Operation (load p.x)3.3. Diese Teilstücke können vom Optimierer daraufhin freier umgeordnet werden; nur Operationen, die global sichtbare Seiteneffekte hervorrufen, dürfen natürlich nicht vor vorhergehende Ausnahmeprüfungen bewegt werden.

Der so erzeugte Code weist zwei Abweichungen von der präzisen Ausnahmedefinition auf:

Es muß daher zusätzlicher Kompensations-Code erzeugt werden, der diese Abweichungen bereinigt. Dieser weist dem Grunde nach die gleiche Struktur wie der optimierte Code auf, es bestehen jedoch die folgenden Unterschiede:

Wird eine Ausnahme ausgelöst, so findet ein Kontrolltransfer an die entsprechende Stelle im Kompensations-Code statt, der den Algorithmus auf korrekte Weise zuende führt.

Abbildung: Generierter Code für p.x = a[i]
\begin{figure}
\begin{center}
\begin{verbatim}try:
trap if a == 0 ; (1) NullP...
...new NullPointerException()
store p.x, r1\end{verbatim} \end{center}\end{figure}

Ein Beispiel verdeutlicht das Vorgehen für den Ausdruck p.x = a[i] (Abbildung 3.5): angenommen, der Null-Test der Referenz p und der Array-Index-Test sind vom Compiler vertauscht worden. Wird nun eine NullPointerException durch Test (2) ausgelöst, so muß der Kompensationscode noch den Array-Test nachvollziehen und u.U. die korrekte ArrayIndexOutOfBoundsException auslösen.

Die Generierung des Kompensationscode verdoppelt den Platzbedarf der Methode. Es wäre daher von Vorteil, diesen bei Bedarf vom dynamischen Compiler erzeugen zu lassen. Ausnahmen sollten daher nicht zur Kontrollflußsteuerung eingesetzt werden, sondern für den Ausnahmefall reserviert sein.


next up previous contents
Next: Zusammenfassung Up: Deoptimierung Previous: On-Stack Replacement   Inhalt

2001-02-28