Feature-Komposition auf Bytecode-Ebene Claus Hunsen Sergiy Kolesnikov Sven Apel FOSD-Treffen 2012
Feature-Komposition Quellcode-Komposition Feature-Module (Quellcode) ➊ Komposition Variante (Quellcode) ➋ Übersetzung Variante (Bytecode) Bytecode-Komposition Feature-Module (Quellcode) ➊ Übersetzung Feature-Module (Bytecode) ➋ Komposition Variante (Bytecode) ➊ Komposition FeatureHouse (AST-Superimposition, ähnlich AHEAD Tool Suite) ➋ Übersetzung Standard-Java-Compiler ➊ Übersetzung Feature-Stubber und Fuji (Feature-orientierter Java-Compiler) ➋ Komposition auf Bytecode-Ebene FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 2/19
Ziel Zu erreichende Punkte separate Übersetzung und Prüfung von Feature-Modulen gewünscht (z.b. Type Checking und Model Checking) Hürden bei Java Kompilieren von Java kontextabhängig stark typisierte Sprache (strenge Typüberprüfung beim Kompilieren) Features sind keine selbstständig kompilierbaren Einheiten. Stub-Generierung für das fehlerlose Kompilieren nötig! Stubs Rumpf-Klassen, die genau soviel Informationen bereitstellen, sodass ein Feature separat kompiliert werden kann FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 3/19
Ablauf Feature-Module (Quellcode) Feature-Stubber Feature-Module + Stubs (Quellcode) Fuji Feature-Module (Bytecode) Bytecode-Komposition Variante (Bytecode) FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 4/19
Ablauf Feature-Module (Quellcode) Feature-Stubber Feature-Module + Stubs (Quellcode) Fuji Feature-Module (Bytecode) Bytecode-Komposition Variante (Bytecode) FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 5/19
Stub-Generierung Feature-Stubber Generierung der Stubs auf Grundlage von globalem Wissen gesamte Produktlinie ist bekannt Referenzen werden ausgewertet Feature-Module zusammen mit Stubs kompilierbar! FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 6/19
Stub-Generierung Beispiel feature1/a.java class A { static int getresult () {return B.calculate(); static String getinput () {return input ; static void flush () {... feature2/b.java class B { static void print () {System. out. println (A.getInput()); static int calculate () {return 27; static void doit () {... Stubs feature1 stubfix/b.java class B { @Stub static int calculate () {return 0; feature2 stubfix/a.java class A { @Stub static String getinput () {return null; FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 7/19
Ablauf Feature-Module (Quellcode) Feature-Stubber Feature-Module + Stubs (Quellcode) Fuji Feature-Module (Bytecode) Bytecode-Komposition Variante (Bytecode) FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 8/19
Übersetzung mit Fuji Ablauf Komposition der einzelnen Feature-Module mit den dazugehörigen Stubs feature1 und feature1 stubfix Übersetzung des Ergebnisses feature1 stubfix classes FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 9/19
Ablauf Feature-Module (Quellcode) Feature-Stubber Feature-Module + Stubs (Quellcode) Fuji Feature-Module (Bytecode) Bytecode-Komposition Variante (Bytecode) FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 10/19
Bytecode?! Wie soll mit Bytecode umgegangen werden? Nutzung des Bytecode-Frameworks ASM http://asm.ow2.org/ Bytecode muss nicht selbst angefasst werden! FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 11/19
Komposition Ablauf 1 Einlesen der Struktur der Produktlinie 2 Komposition der Klassen Erkennung von Stubs (Annotation @Stub) Komposition von Methoden und Feldern Entfernung der Stubs 3 Verifizierung der komponierten Klassen mit ASM (optional) Algorithmen Feature für Feature wird mit der Basis zusammengeführt Basisklasse ist fest eingelesen. Klassenverfeinerung wird mittels Visitor-Pattern untersucht. Kompositionsregeln entsprechend der Superimposition von FeatureHouse FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 12/19
Bytecode-Eigenheiten I Innere und anonyme Klassen Innere und anonyme Klassen haben eigene Dateien für ihren Bytecode. (bspw. A$1.class und A$Inner.class) Benannte innere Klassen werden komponiert wie äußere. Anonyme Klassen feature1/a$1.class und feature2/a$1.class müssen nicht identisch sein! Anonyme Klassen müssen umbenannt werden! feature1/a$1.class feature1/a$feature1 1.class feature2/a$1.class feature2/a$feature2 1.class FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 13/19
Bytecode-Eigenheiten II Zusammenführung von Konstruktoren Jeder Konstruktor enthält einen super()-aufruf im Bytecode, der explizit den Namen der Superklasse enthält. Ein Aufruf muss entfernt werden! Änderung der Superklasse Der Name der Superklasse steht auch im Konstruktor (super()-aufruf) und muss auch dort geändert werden! FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 14/19
Laufzeitvergleich Bytecode-Komposition FeatureHouse 1750 1500 Laufzeit [ms] 1250 1000 750 500 250 0 Testsuite EPL GPL Notepad Violet BK mit Verifizierung BK ohne Verifizierung FeatureHouse FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 15/19
Anmerkungen und Vorteile Der Vergleich hinkt! Annahme: Wir wollen alle Varianten der Produktlinie generieren. Quellcode-Komposition:(2 n t sourcecode-comp )+(2 n t compile-product ) Bytecode-Komposition: (n t compile-feature )+(2 n t bytecode-comp ) Weitere Vorteile besser für feature-basierte Analysen Type Checking Model Checking statische Analyse... FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 16/19
Ausblick Gegenwart: Closed World Stub-Generierung auf Grundlage von globalem Wissen Zukunft: Open World Erzeugung von polymorphem Bytecode [vgl. Ancona et al., POPL 05] Polymorpher Bytecode: Kompositionelle Übersetzung nicht mehr kontextabhängig Typvariablen und dazugehörige Beschränkungen im Bytecode nicht trivial, aber umsetzbar! FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 17/19
Polymorpher Bytecode - Beispiel class Client { JFrame getframe() { return this. frame ; class Client { JFrame frame = new JFrame(); getfield Client.frame:JFrame class Client { SpecialFrame frame = new SpecialFrame(); // SpecialFrame extends JFrame getfield Client.frame:SpecialFrame FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 18/19
Polymorpher Bytecode - Beispiel class Client { JFrame getframe() { return this. frame ; Polymorpher Bytecode für das Feature GUI getfield Client.frame:α {α JFrame FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 18/19
Diskussion Claus Hunsen hunsen@fim.uni-passau.de FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 19/19
Implementierung (Auszug) ComposingClassVisitor für Klassen visit untersucht u.a. die Superklasse visitfield untersucht jedes Feld des Features einzeln visitmethod untersucht jede Methode des Features einzeln (auch Konstruktoren) StubDetector für Methoden und Felder visitannotation überprüft auf die Annotation @Stub isstub gibt das Ergebnis zurück MethodAdapter für Methoden StubDetector-Implementierung visitmethodinsn nimmt original-umbenennungen vor FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 20
Feature-Komposition mit FeatureHouse Beispiel // Basis class Client { void doit () { System. out. println ( I did it. ); // Feature class Client extends JFrame { void doit () { original(); System. out. println (... some other way. ); // Komposition class Client extends JFrame { void $ Basis $ doit () { System. out. println ( I did it. ); void doit () { $ Basis $ doit(); System. out. println (... some other way. ); = FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 21
Implementierung public MethodVisitor visitmethod ( int access, String name, String desc, String signature, String [] exceptions ) { // representative object for current feature method MethodNode featmethod = new MethodNode(access,name, desc, signature, exceptions ); // get corresponding base method if existing MethodNode basemethod = t h i s. getbasemethodforfeaturemethod( featmethod ); // obtain the method visitor so far MethodVisitor mv = this. cv. visitmethod (access,name, desc, signature, exceptions ); // change SUPER CALL in constructor if super class was changed... // CONSTRUCTOR if (featmethod. isconstructor ()) { mv = new ConstructorMergeAdapter(mv, featmethod, basemethod ); // NORMAL METHODS: stub detection, original call renaming and overwriting else { mv = new MethodAdapter(mv, featmethod); // return method visitor return mv; FOSD-Treffen 2012 Feature-Komposition auf Bytecode-Ebene 22