Übungen zur Vorlesung Systemarchitektur und -Software WS 2002/2003 Forschungsgruppe Systemarchitektur und –Software Ausgabe: 02.12.02 Abgabe: 06.01.03 Dr. R. Riedl Silvio Meier Übung 3 (Java Stack, Class-File-Struktur, Java Instruktionssatz) Informationen zum Java Instruktionssatz finden Sie in der zur Vorlesung empfohlenen Literatur oder auf der Sun-Web-Seite: http://java.sun.com/docs/books/vmspec/html/Instructions.doc.html Aufgabe 1 (Java Stack) [7 Punkte + 1 Bonus-Punkt] a. Erklären Sie kurz wozu der Java Stack benötigt wird, wie er aufgebaut ist, und wie der Java Stack in Beziehung mit Threads steht. Beantworten Sie zudem, wie die einzelnen Datentypen auf dem Java-Stack dargestellt werden. [2 Punkte] b. Folgender Code sei gegeben: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class JavaStackTest { public static void main(String[] args){ Computation c = new Computation(42); System.out.println(c.sophisticatedComputation(33)); } } class Computation { private int seed; public Computation(int seed) { this.seed = seed; } public long sophisticatedComputation(int var) { int a = var; int b = var * 2; int c = var * 3; return specialSum(a,b,c); } public long specialSum(int a, int b, int c){ int swap; long result = 0; swap = a; a = c; c = swap; result = a + b * b + c * c * c + seed; seed = (int)(result / 2); return result; } } Berechnen Sie für die beiden oben stehenden Methoden sophisticatedComputation und specialSum jeweils, wie viel Platz maximal auf dem Java Stack benötigt wird (für die lokalen Variablen sowie für den Operanden-Stack). [2 Punkte] c. Zeichnen Sie den Java Stack schematisch auf, unter der Annahme, dass sich obiges Programm vor Zeile 22 aber nach Zeile 21 in der Ausführung befindet. Zeigen Sie, was sich je im Bereich der lokalen Variablen und dem Operanden-Stack befindet. Erläutern Sie. [3 Punkte] d. Was passiert auf dem Java-Stack genau, wenn in einer Methode eine Exception geworfen und diese nicht abgefangen wird? Zeigen Sie dies anhand eines konkreten Beispiels [1 Bonus-Punkt]. Aufgabe 2 – (Java Instruktionssatz – Grundlagen) [8 Punkte] a. Folgender disassemblierter (in mnemonischer Form) Bytecode einer Java-Methode ist gegeben: 0 iload_1 1 iload_0 15 goto 26 18 iload_1 2 5 6 7 8 9 10 11 12 13 14 if_icmple 11 iload_1 istore_2 iload_0 istore_1 iload_2 istore_0 iload_0 iload_1 irem istore_3 19 20 21 22 23 24 25 26 27 30 31 istore_0 iload_3 istore_1 iload_0 iload_1 irem istore_3 iload_3 ifne 18 iload_1 ireturn Rekonstruieren Sie die ursprüngliche Java-Methode von Hand und beschreiben Sie, was diese Methode macht. Wie viele lokale Variablen verwendet diese Methode, von welchem Typ sind diese lokalen Variablen? Ist die Methode eine Klassen- oder Instanzmethode? [5 Punkte] b. Folgende (Instanz-)Methode ist in Java gegeben: public int integerMultiply(int factor1, int factor2){ int result = 0; for (int i=0; i < factor1; i++){ result = result + factor2; } return result; } Diese Methode multipliziert zwei Integer-Zahlen. Übersetzen Sie diese Methode in Java Bytecode. Sie können anstelle von konkreten Offsets im Bytecode auch symbolische Sprungmarken (Labels) verwenden. [3 Punkte] Aufgabe 3 (Java-Class-Files) [4 Punkte] Auf dem Markt sind sogenannte Decompiler verfügbar, mit denen (kompilierte) JavaClassfiles wieder dekompiliert, d.h. wieder in Source Code umgewandelt werden können. Für interessierte Studierende: Ein sehr guter, frei verfügbarer Decompiler ist z.B. unter http://kpdus.tripod.com/jad.html zu finden. a. Versuchen Sie anhand der Java-Class-File-Struktur herauszufinden warum kompilierter Java Code wieder dekompiliert werden kann. Nennen Sie mehrere Gründe warum dies so ist. [2 Punkte] b. Was könnte man machen, damit Java-Class-Files nicht mehr so einfach dekompilierbar sind? [2 Punkte] Aufgabe 4 (Methodenaufrufe) [5 Punkte] Polymorphie ist ein wichtiges Konzept in der objektorientierten Softwareentwicklung. U.a. wird dieses Konzept durch sogenanntes dynamisches Binden unterstützt. Gegeben sei folgender Java-Code: 1 public class DynamicBinding { 2 public static void main(String[] args) { 3 Base b = new InheritedClass(); 4 b.methodCaller(); 5 } 6 } 7 class Base { 8 public Base() { 9 } 10 public void publicMethod() { 11 System.out.println("super class public method"); 12 } 13 protected void protectedMethod() { 14 System.out.println("super class protected method"); 15 } 16 private void privateMethod() { 17 System.out.println("super class private method"); 18 } 19 public void methodCaller() 20 { 21 publicMethod(); 22 // 0 0:aload_0 23 // 1 1:invokevirtual #7 <Method void publicMethod()> 24 protectedMethod(); 25 // 2 4:aload_0 26 // 3 5:invokevirtual #8 <Method void protectedMethod()> 27 privateMethod(); 28 // 4 8:aload_0 29 // 5 9:invokespecial #9 <Method void privateMethod()> 30 // 6 12:return 31 } 32 } 33 class InheritedClass extends Base { 34 public void publicMethod() { 35 System.out.println("sub class public method"); 36 } 37 protected void protectedMethod() { 38 System.out.println("sub class protected method"); 39 } 40 private void privateMethod() { 41 System.out.println("sub class private method"); 42 } 42 } Wird das Programm durch das Ausführen der Klasse DynamicBinding gestartet, so wird folgendes ausgegeben: sub class public method sub class protected method super class private method a. Was für Operanden liegen auf dem Operanden-Stack unmittelbar vor der Ausführung der Methode publicMehtod(). Sie müssen keine konkreten Werte nennen, sondern nur die Typen der Daten und wieviele Bytes diese belegen. Beschreiben Sie kurz für welchen Zweck diese Operanden für den Methodenaufruf benötigt werden. [1 Punkt] b. Versuchen Sie anhand der resultierenden Ausgabe die unterschiedliche Funktionsweise der Bytecodeinstruktion invokespecial und invokevirtual zu beschreiben. Dazu finden Sie in der Methode methodCaller() die Bytecodeinstruktionen als Kommentar zu jedem Methodenaufzuf zugeordnet. [3 Punkte] c. Beschreiben Sie ganz kurz was bei der Instruktion return bzw. areturn, ireturn, dreturn, freturn und lreturn passiert. [1 Punkt] Aufgabe 5 (Switch-Statement) [6 Punkte] a. Erklären Sie ganz kurz den Unterschied zwischen lookupswitch und tableswitch Instruktion. [1 Punkt] b. Folgende Methode sei gegeben: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void main(String[] args) { int a = 3; int b = 0; switch (a) { case 1: b = b * a; break; case 5: b = b * 3; break; default: b = 0; } int c; switch (b) { case 4: c = 3; break; case 5: 21 22 21 23 24 23 24 25 } 26 } c = 2 * b; break; case 6: c = 7; break; default: c = 0; Übersetzen Sie diese Java-Methode in mnemonischen Bytecode. Sie können dabei anstelle von konkreten Offsets symbolische Sprungmarken verwenden (labels). Orientieren Sie sich an den Beispielen auf den Vorlesungsfolien 70 und 71. [4 Punkte] c. Gegeben sei folgendes Java-Codefragment: char d; int b; ... switch (b) { case 4: d = 'A'; case 5: d = 'B'; default: d = 'C'; } Dieser Code wird durch einen Java Compiler wie folgt in Bytecode übersetzt: 79 iload_2 80 lookupswitch 2: default=116 4: 108 5: 112 108 bipush 65 110 istore 4 112 bipush 66 114 istore 4 116 bipush 67 117 istore 4 Inwiefern entspricht diese Übersetzung nicht Ihren Erwartungen? Haben Sie eine Erklärung warum das oben stehende Codefragment so übersetzt wird? Versuchen Sie mit Hilfe der Informationen, die Sie in der angegebenen Literatur finden, eine Erklärung zu finden. [1 Punkt]