From d0267aa960c546b94addc6afe2f0691a6b5b9a3f Mon Sep 17 00:00:00 2001 From: JanUlrich Date: Thu, 27 Aug 2015 13:36:14 +0200 Subject: [PATCH] Bytecode erweitert --- BCEL/bcelifier/IntLiteral.java | 7 ++ BCEL/bcelifier/IntLiteralCreator.java | 56 ++++++++++++ BCEL/bcelifier/JavaToBCEL.java | 37 ++++++++ BCEL/bcelifier/Lambda1.class.toGenerate | Bin 0 -> 982 bytes BCEL/bcelifier/Lambda1.java | 8 ++ BCEL/bcelifier/Lambda1Creator.java | 70 +++++++++++++++ BCEL/bcelifier/MethodCall.java | 12 +++ BCEL/bcelifier/MethodCallCreator.java | 70 +++++++++++++++ BCEL/bcelifier/This.java | 8 ++ BCEL/bcelifier/ThisCreator.java | 55 ++++++++++++ .../bytecode/DHBWInstructionFactory.java | 80 ++++++++++++++++++ src/de/dhbwstuttgart/core/MyCompiler.java | 22 ++--- src/de/dhbwstuttgart/core/MyCompilerAPI.java | 7 +- src/de/dhbwstuttgart/syntaxtree/Class.java | 14 +-- src/de/dhbwstuttgart/syntaxtree/Method.java | 20 ++++- .../syntaxtree/ParameterList.java | 4 + .../dhbwstuttgart/syntaxtree/SourceFile.java | 18 +++- .../syntaxtree/statement/IntLiteral.java | 14 ++- .../syntaxtree/statement/MethodCall.java | 3 +- .../syntaxtree/statement/Return.java | 5 +- test/bytecode/AssignTest.java | 17 +--- test/bytecode/BoolLitTest.java | 13 +-- test/bytecode/CharLitTest.java | 13 +-- test/bytecode/EmptyClassTest.java | 13 +-- test/bytecode/MethodCall.jav | 9 ++ test/bytecode/MethodCallTest.java | 34 ++++++++ test/bytecode/Return.jav | 9 +- test/bytecode/ReturnTest.java | 19 +---- test/bytecode/SingleClassTester.java | 32 +++++++ test/bytecode/Test.java | 4 +- 30 files changed, 564 insertions(+), 109 deletions(-) create mode 100644 BCEL/bcelifier/IntLiteral.java create mode 100644 BCEL/bcelifier/IntLiteralCreator.java create mode 100644 BCEL/bcelifier/JavaToBCEL.java create mode 100644 BCEL/bcelifier/Lambda1.class.toGenerate create mode 100644 BCEL/bcelifier/Lambda1.java create mode 100644 BCEL/bcelifier/Lambda1Creator.java create mode 100644 BCEL/bcelifier/MethodCall.java create mode 100644 BCEL/bcelifier/MethodCallCreator.java create mode 100644 BCEL/bcelifier/This.java create mode 100644 BCEL/bcelifier/ThisCreator.java create mode 100644 src/de/dhbwstuttgart/bytecode/DHBWInstructionFactory.java create mode 100644 test/bytecode/MethodCall.jav create mode 100644 test/bytecode/MethodCallTest.java create mode 100644 test/bytecode/SingleClassTester.java diff --git a/BCEL/bcelifier/IntLiteral.java b/BCEL/bcelifier/IntLiteral.java new file mode 100644 index 000000000..a4d38fe93 --- /dev/null +++ b/BCEL/bcelifier/IntLiteral.java @@ -0,0 +1,7 @@ +package bcelifier; + +public class IntLiteral { + Integer methode(){ + return 50000; + } +} diff --git a/BCEL/bcelifier/IntLiteralCreator.java b/BCEL/bcelifier/IntLiteralCreator.java new file mode 100644 index 000000000..eed6f1379 --- /dev/null +++ b/BCEL/bcelifier/IntLiteralCreator.java @@ -0,0 +1,56 @@ +package bcelifier; + +import org.apache.bcel.generic.*; +import org.apache.bcel.classfile.*; +import org.apache.bcel.*; +import java.io.*; + +public class IntLiteralCreator implements Constants { + private InstructionFactory _factory; + private ConstantPoolGen _cp; + private ClassGen _cg; + + public IntLiteralCreator() { + _cg = new ClassGen("bcelifier.IntLiteral", "java.lang.Object", "IntLiteral.java", ACC_PUBLIC | ACC_SUPER, new String[] { }); + + _cp = _cg.getConstantPool(); + _factory = new InstructionFactory(_cg, _cp); + } + + public void create(OutputStream out) throws IOException { + createMethod_0(); + createMethod_1(); + _cg.getJavaClass().dump(out); + } + + private void createMethod_0() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] { }, "", "bcelifier.IntLiteral", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0)); + il.append(_factory.createInvoke("java.lang.Object", "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); + InstructionHandle ih_4 = il.append(_factory.createReturn(Type.VOID)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + private void createMethod_1() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(0, new ObjectType("java.lang.Integer"), Type.NO_ARGS, new String[] { }, "methode", "bcelifier.IntLiteral", il, _cp); + + InstructionHandle ih_0 = il.append(new PUSH(_cp, 50000)); + il.append(_factory.createInvoke("java.lang.Integer", "valueOf", new ObjectType("java.lang.Integer"), new Type[] { Type.INT }, Constants.INVOKESTATIC)); + InstructionHandle ih_5 = il.append(_factory.createReturn(Type.OBJECT)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + public static void main(String[] args) throws Exception { + bcelifier.IntLiteralCreator creator = new bcelifier.IntLiteralCreator(); + creator.create(new FileOutputStream("bcelifier.IntLiteral.class")); + } +} diff --git a/BCEL/bcelifier/JavaToBCEL.java b/BCEL/bcelifier/JavaToBCEL.java new file mode 100644 index 000000000..574f6b7ca --- /dev/null +++ b/BCEL/bcelifier/JavaToBCEL.java @@ -0,0 +1,37 @@ +package bcelifier; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.OpenOption; +import java.nio.file.Path; + +import org.apache.bcel.classfile.ClassFormatException; +import org.apache.bcel.classfile.ClassParser; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.util.BCELifier; + +public class JavaToBCEL { + + public final static String rootDirectory = System.getProperty("user.dir")+"/BCEL/bcelifier/"; + + public static void main(String args[]){ + new JavaToBCEL(); + } + + public JavaToBCEL(){ + try { + new BCELifier(new ClassParser(rootDirectory+"Lambda1.class").parse(), new FileOutputStream(new File(rootDirectory+"Lambda1Creator.java"))).start(); + new BCELifier(new ClassParser(rootDirectory+"This.class").parse(), new FileOutputStream(new File(rootDirectory+"ThisCreator.java"))).start(); + new BCELifier(new ClassParser(rootDirectory+"IntLiteral.class").parse(), new FileOutputStream(new File(rootDirectory+"IntLiteralCreator.java"))).start(); + new BCELifier(new ClassParser(rootDirectory+"MethodCall.class").parse(), new FileOutputStream(new File(rootDirectory+"MethodCallCreator.java"))).start(); + + } catch (ClassFormatException | IOException e) { + e.printStackTrace(); + } + } + + +} diff --git a/BCEL/bcelifier/Lambda1.class.toGenerate b/BCEL/bcelifier/Lambda1.class.toGenerate new file mode 100644 index 0000000000000000000000000000000000000000..c82ddc6f846f03d4d1a3a34518db83997a3f2ae5 GIT binary patch literal 982 zcmbVLO>fgc5Ph38-qbZDZAhU&KPYKQ0yGqH3*tZ|1X7@gRK0JKZM&_rj_h@%{43x9 zQV;w9#BV~(#zt`|^nedLv$JpB%)DKH|9Somz%x8`;h?-kesvzpxar~+Ryb~R++lE@ zE3M26hJ3woz%bVdhLWMwRa(A_M|~OYi@r}0K9c5mdbV6|bWg;YX!$}PwLZjJTSS|o z?2A!ceqewX~gTO>46yvv3{;1^OZW+ZA$Et@l ztaEI5xQ9)S`yOi8Vp!}Cq^}N@3|lE7(aaj!>z~Mhaj}gDE()mAWMQls8ujj_#P+`? znbGwok&z=J31Y)gO(s`C>wT!S>6uW95shA%CR_}YW@8KTsd%-Xku2%3-8kTAcxYnB z!!@hL=B%pHXThmV=Obmrp%|DToG>hqy1#cEB(c*Cg41|R^1jhph8#m9{Mt>C5i1!XEcw}N7=}Q#Qn)w{@-Cz^6K2|U8H3@!uNa1$Tr6=!`3Bz{x%Q8 z+SNFEO$GWP?3V{!5{k6W({7b4BU@;G1^Yw}ySystem.out.println(this); + } +} diff --git a/BCEL/bcelifier/Lambda1Creator.java b/BCEL/bcelifier/Lambda1Creator.java new file mode 100644 index 000000000..f7f6f8a57 --- /dev/null +++ b/BCEL/bcelifier/Lambda1Creator.java @@ -0,0 +1,70 @@ +package bcelifier; + +import org.apache.bcel.generic.*; +import org.apache.bcel.classfile.*; +import org.apache.bcel.*; +import java.io.*; + +public class Lambda1Creator implements Constants { + private InstructionFactory _factory; + private ConstantPoolGen _cp; + private ClassGen _cg; + + public Lambda1Creator() { + _cg = new ClassGen("bcelifier.Lambda1", "java.lang.Object", "Lambda1.java", ACC_PUBLIC | ACC_SUPER, new String[] { }); + + _cp = _cg.getConstantPool(); + _factory = new InstructionFactory(_cg, _cp); + } + + public void create(OutputStream out) throws IOException { + createMethod_0(); + createMethod_1(); + createMethod_2(); + _cg.getJavaClass().dump(out); + } + + private void createMethod_0() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] { }, "", "bcelifier.Lambda1", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0)); + il.append(_factory.createInvoke("java.lang.Object", "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); + InstructionHandle ih_4 = il.append(_factory.createReturn(Type.VOID)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + private void createMethod_1() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(0, new ObjectType("java.lang.Runnable"), Type.NO_ARGS, new String[] { }, "methode", "bcelifier.Lambda1", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0)); + InstructionHandle ih_1 = il.append(_factory.createReturn(Type.OBJECT)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + private void createMethod_2() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(ACC_PRIVATE | ACC_SYNTHETIC, Type.VOID, Type.NO_ARGS, new String[] { }, "lambda$methode$0", "bcelifier.Lambda1", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createFieldAccess("java.lang.System", "out", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC)); + il.append(_factory.createLoad(Type.OBJECT, 0)); + il.append(_factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.OBJECT }, Constants.INVOKEVIRTUAL)); + InstructionHandle ih_7 = il.append(_factory.createReturn(Type.VOID)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + public static void main(String[] args) throws Exception { + bcelifier.Lambda1Creator creator = new bcelifier.Lambda1Creator(); + creator.create(new FileOutputStream("bcelifier.Lambda1.class")); + } +} diff --git a/BCEL/bcelifier/MethodCall.java b/BCEL/bcelifier/MethodCall.java new file mode 100644 index 000000000..433957b3a --- /dev/null +++ b/BCEL/bcelifier/MethodCall.java @@ -0,0 +1,12 @@ +package bcelifier; + +public class MethodCall { + void methode(){ + } + + void methode2(Runnable r){ + methode(); + r.run(); + } +} + diff --git a/BCEL/bcelifier/MethodCallCreator.java b/BCEL/bcelifier/MethodCallCreator.java new file mode 100644 index 000000000..303fb699b --- /dev/null +++ b/BCEL/bcelifier/MethodCallCreator.java @@ -0,0 +1,70 @@ +package bcelifier; + +import org.apache.bcel.generic.*; +import org.apache.bcel.classfile.*; +import org.apache.bcel.*; +import java.io.*; + +public class MethodCallCreator implements Constants { + private InstructionFactory _factory; + private ConstantPoolGen _cp; + private ClassGen _cg; + + public MethodCallCreator() { + _cg = new ClassGen("bcelifier.MethodCall", "java.lang.Object", "MethodCall.java", ACC_PUBLIC | ACC_SUPER, new String[] { }); + + _cp = _cg.getConstantPool(); + _factory = new InstructionFactory(_cg, _cp); + } + + public void create(OutputStream out) throws IOException { + createMethod_0(); + createMethod_1(); + createMethod_2(); + _cg.getJavaClass().dump(out); + } + + private void createMethod_0() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] { }, "", "bcelifier.MethodCall", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0)); + il.append(_factory.createInvoke("java.lang.Object", "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); + InstructionHandle ih_4 = il.append(_factory.createReturn(Type.VOID)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + private void createMethod_1() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(0, Type.VOID, Type.NO_ARGS, new String[] { }, "methode", "bcelifier.MethodCall", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createReturn(Type.VOID)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + private void createMethod_2() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(0, Type.VOID, new Type[] { new ObjectType("java.lang.Runnable") }, new String[] { "arg0" }, "methode2", "bcelifier.MethodCall", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0)); + il.append(_factory.createInvoke("bcelifier.MethodCall", "methode", Type.VOID, Type.NO_ARGS, Constants.INVOKEVIRTUAL)); + InstructionHandle ih_4 = il.append(_factory.createLoad(Type.OBJECT, 1)); + il.append(_factory.createInvoke("java.lang.Runnable", "run", Type.VOID, Type.NO_ARGS, Constants.INVOKEINTERFACE)); + InstructionHandle ih_10 = il.append(_factory.createReturn(Type.VOID)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + public static void main(String[] args) throws Exception { + bcelifier.MethodCallCreator creator = new bcelifier.MethodCallCreator(); + creator.create(new FileOutputStream("bcelifier.MethodCall.class")); + } +} diff --git a/BCEL/bcelifier/This.java b/BCEL/bcelifier/This.java new file mode 100644 index 000000000..3d239478c --- /dev/null +++ b/BCEL/bcelifier/This.java @@ -0,0 +1,8 @@ +package bcelifier; + +public class This { + + This methode(){ + return this; + } +} diff --git a/BCEL/bcelifier/ThisCreator.java b/BCEL/bcelifier/ThisCreator.java new file mode 100644 index 000000000..329d0d5d8 --- /dev/null +++ b/BCEL/bcelifier/ThisCreator.java @@ -0,0 +1,55 @@ +package bcelifier; + +import org.apache.bcel.generic.*; +import org.apache.bcel.classfile.*; +import org.apache.bcel.*; +import java.io.*; + +public class ThisCreator implements Constants { + private InstructionFactory _factory; + private ConstantPoolGen _cp; + private ClassGen _cg; + + public ThisCreator() { + _cg = new ClassGen("bcelifier.This", "java.lang.Object", "", ACC_PUBLIC | ACC_SUPER, new String[] { }); + + _cp = _cg.getConstantPool(); + _factory = new InstructionFactory(_cg, _cp); + } + + public void create(OutputStream out) throws IOException { + createMethod_0(); + createMethod_1(); + _cg.getJavaClass().dump(out); + } + + private void createMethod_0() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] { }, "", "bcelifier.This", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0)); + il.append(_factory.createInvoke("java.lang.Object", "", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); + InstructionHandle ih_4 = il.append(_factory.createReturn(Type.VOID)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + private void createMethod_1() { + InstructionList il = new InstructionList(); + MethodGen method = new MethodGen(0, new ObjectType("bcelifier.This"), Type.NO_ARGS, new String[] { }, "methode", "bcelifier.This", il, _cp); + + InstructionHandle ih_0 = il.append(_factory.createLoad(Type.OBJECT, 0)); + InstructionHandle ih_1 = il.append(_factory.createReturn(Type.OBJECT)); + method.setMaxStack(); + method.setMaxLocals(); + _cg.addMethod(method.getMethod()); + il.dispose(); + } + + public static void main(String[] args) throws Exception { + bcelifier.ThisCreator creator = new bcelifier.ThisCreator(); + creator.create(new FileOutputStream("bcelifier.This.class")); + } +} diff --git a/src/de/dhbwstuttgart/bytecode/DHBWInstructionFactory.java b/src/de/dhbwstuttgart/bytecode/DHBWInstructionFactory.java new file mode 100644 index 000000000..bec3f0769 --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/DHBWInstructionFactory.java @@ -0,0 +1,80 @@ +package de.dhbwstuttgart.bytecode; + +import java.awt.List; +import java.util.ArrayList; + +import org.apache.bcel.classfile.BootstrapMethod; +import org.apache.bcel.classfile.ConstantInvokeDynamic; +import org.apache.bcel.classfile.Method; +import org.apache.bcel.generic.ClassGen; +import org.apache.bcel.generic.ConstantPoolGen; +import org.apache.bcel.generic.INVOKEDYNAMIC; +import org.apache.bcel.generic.InstructionFactory; +import org.apache.bcel.generic.MethodGen; +import org.apache.bcel.generic.Type; + +public class DHBWInstructionFactory extends InstructionFactory{ + + public DHBWInstructionFactory(ClassGen cg, ConstantPoolGen cp) { + super(cg, cp); + } + + private BootstrapMethod createBootstrapMethod(){ + //TODO + return null; + } + + public INVOKEDYNAMIC createInvokeDynamic( MethodGen lambdaMethod ) { + //Zuerst die Bootstrap-Methode erstellen: Diese müssen dann in ein BootstrapMethods-Attribut zusammengefasst und dem Classfile hinzugefügt werden + int lambdaMethodIndex = this.cp.addMethodref(lambdaMethod); + + ArrayList arguments = new ArrayList(); + + BootstrapMethod bMethod = new BootstrapMethod(lambdaMethodIndex, arguments.size(), (int[])arguments.toArray()); + + final short opcode = 186; + int index; + /* + int nargs = 0; + String signature = Type.getMethodSignature(ret_type, arg_types); + for (int i = 0; i < arg_types.length; i++) { + nargs += arg_types[i].getSize(); + } + */ + + //index = cp.addInvokeDynamic(bootstrap_index, name, signature); + //Adding invokeDynamic to Constant_Pool: + + /* + * Spezifikation: @see https://docs.oracle.com/javase/specs/jvms/se8/html/index.html + * + * CONSTANT_InvokeDynamic_info structure: + * - a symbolic reference to a method handle (bootstrap_method_attr_index) + * - a method name and a method descriptor (name_and_type_index) + * + * @see https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.10 + */ + + /* + * + * TODO: Rausfinden, was es mit der Inneren Klasse auf sich hat + * (public static final #48= #47 of #51; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles + * + * TODO: Rausfinden was es mit dem NameAndType Eintrag in der InvokeDynamic_info Struktur auf sich hat: + * Für ein Runnable ()->{}; ist es: run:(LLambda3;)Ljava/lang/Runnable; + * + * TODO: bootstrap_methode den Klassenattributen hinzufügen + * + */ + + int bootstrap_method_attr_index = bMethod.getBootstrapMethodRef(); + int name_and_type_index = cp.addNameAndType(lambdaMethod.getName(), lambdaMethod.getType().getSignature()); + + ConstantInvokeDynamic cInvokeDynamic = new ConstantInvokeDynamic(bootstrap_method_attr_index, name_and_type_index); + + index = cp.addConstant(cInvokeDynamic, cp); + + return new INVOKEDYNAMIC(opcode, index); + } + +} diff --git a/src/de/dhbwstuttgart/core/MyCompiler.java b/src/de/dhbwstuttgart/core/MyCompiler.java index 5c066ceea..f6a6312b1 100755 --- a/src/de/dhbwstuttgart/core/MyCompiler.java +++ b/src/de/dhbwstuttgart/core/MyCompiler.java @@ -855,22 +855,14 @@ public class MyCompiler implements MyCompilerAPI } @Override - public ByteCodeResult generateBytecode() { - /* - * TODO Für das Bytecode-Team: - * - generateBytecode-Methode implementieren - * - Sich einen passenden Container für den Bytecode überlegen - * - Dieser wird von generateBytecode zurückgeliefert und sollte die Möglichkeit zum schreiben von Bytecode in eine Datei bieten. - * - wird der Rückgabetyp von generateBytecode in MyCompiler geändert, so muss auch der Rückgabetyp im Interface MyCompilerAPI geändert werden - */ - try { - SourceFile parsedFile = this.m_AbstractSyntaxTree.firstElement(); - Class parsedClass = parsedFile.KlassenVektor.firstElement(); - return parsedClass.genByteCode(); - } catch (IOException e) { - e.printStackTrace(); - return null; + public Menge generateBytecode() { + //SourceFile parsedFile = this.m_AbstractSyntaxTree.firstElement(); + //Class parsedClass = parsedFile.KlassenVektor.firstElement(); + Menge ret = new Menge<>(); + for(SourceFile sf : this.m_AbstractSyntaxTree){ + ret.addAll(sf.generateBytecode()); } + return ret; } } // ino.end diff --git a/src/de/dhbwstuttgart/core/MyCompilerAPI.java b/src/de/dhbwstuttgart/core/MyCompilerAPI.java index 2898b3bae..f1c8880e6 100755 --- a/src/de/dhbwstuttgart/core/MyCompilerAPI.java +++ b/src/de/dhbwstuttgart/core/MyCompilerAPI.java @@ -122,6 +122,11 @@ public interface MyCompilerAPI */ public SourceFile parse(String sourceCode) throws ParserError; - public ByteCodeResult generateBytecode(); + /** + * Generiert für jede geparste Klasse im SourceFile ein ByteCodeResult. + * Dafür müssen die Schritte Parsen und typeReconstruction ausgeführt werden. + * @return + */ + public Menge generateBytecode(); } // ino.end diff --git a/src/de/dhbwstuttgart/syntaxtree/Class.java b/src/de/dhbwstuttgart/syntaxtree/Class.java index e2dec91b6..bc16e212b 100755 --- a/src/de/dhbwstuttgart/syntaxtree/Class.java +++ b/src/de/dhbwstuttgart/syntaxtree/Class.java @@ -72,13 +72,13 @@ public class Class extends GTVDeclarationContext implements AClassOrInterface, I private ClassGen _cg; //Method created with BCEL to generate ByteCode - public ByteCodeResult genByteCode() throws IOException { + public ByteCodeResult genByteCode() { SectionLogger logger = Logger.getSectionLogger(this.getClass().getName(), Section.CODEGEN); logger.debug("Test"); if(pkgName != null)throw new NotImplementedException(); - _cg = new ClassGen(name, superClass.get_Name(), name + ".java", Constants.ACC_PUBLIC , new String[] { }); //new String necessary? + _cg = new ClassGen(name, superClass.get_Name(), name + ".java", Constants.ACC_PUBLIC , new String[] { }); //letzter Parameter sind implementierte Interfaces _cp = _cg.getConstantPool(); _factory = new InstructionFactory(_cg, _cp); @@ -88,12 +88,6 @@ public class Class extends GTVDeclarationContext implements AClassOrInterface, I ByteCodeResult code = new ByteCodeResult(_cg); return code; - - //ByteCodeResult bc = new ByteCodeResult(); - //_cg = new ClassGen(pkgName.get_Name() + "/" + name, superClass.get_Name(), name + ".java", Constants.ACC_PUBLIC , new String[] { }); - //_cg zur�ckgeben - //bc.append(BCELByteCodeOutput); - //return _cg; } private Menge superif = new Menge(); @@ -477,7 +471,7 @@ public class Class extends GTVDeclarationContext implements AClassOrInterface, I */ if(m.get_Method_Name().equals(""))throw new TypeinferenceException(" ist kein gültiger Methodenname", m); if((m.get_Method_Name().equals(this.getName()))) { - Constructor constructor = new Constructor(m); + Constructor constructor = new Constructor(m, this); tempFields.add(constructor); //Den Konstruktor anstatt der Methode anfügen }else{ //Handelt es sich um keinen Konstruktor, dann die Methode unverändert den Feldern hinzufügen: @@ -1251,7 +1245,7 @@ public class Class extends GTVDeclarationContext implements AClassOrInterface, I if(!constructorVorhanden){//Falls kein Konstruktor vorhanden ist, muss noch der Standardkonstruktor angefügt werden: Block konstruktorBlock = new Block(); konstruktorBlock.statements.add(new SuperCall(konstruktorBlock)); - Constructor standardKonstruktor = new Constructor(Method.createEmptyMethod(konstruktorBlock,this.getName().toString(), this)); + Constructor standardKonstruktor = new Constructor(Method.createEmptyMethod(konstruktorBlock,this.getName().toString(), this), this); //Constructor standardKonstruktor = new Constructor(Method.createEmptyMethod(this.getName().toString(), this)); this.addField(standardKonstruktor); diff --git a/src/de/dhbwstuttgart/syntaxtree/Method.java b/src/de/dhbwstuttgart/syntaxtree/Method.java index c5547f235..feb39437c 100755 --- a/src/de/dhbwstuttgart/syntaxtree/Method.java +++ b/src/de/dhbwstuttgart/syntaxtree/Method.java @@ -746,7 +746,23 @@ public class Method extends Field implements IItemWithOffset, TypeInsertable InstructionList il = new InstructionList(); Class parentClass = this.getParentClass(); - MethodGen method = new MethodGen(Constants.ACC_PUBLIC, this.getType().getBytecodeType(), org.apache.bcel.generic.Type.NO_ARGS , new String[] { }, this.get_Method_Name(), parentClass.name, il, _cp); + //Die Argumentliste generieren: + org.apache.bcel.generic.Type[] argumentTypes = org.apache.bcel.generic.Type.NO_ARGS; + String[] argumentNames = new String[]{}; + if(this.parameterlist != null && + this.parameterlist.size() > 0){ + argumentTypes = new org.apache.bcel.generic.Type[this.parameterlist.size()]; + argumentNames = new String[this.parameterlist.size()]; + int i = 0; + for(FormalParameter parameter : this.parameterlist){ + argumentTypes[i] = parameter.getType().getBytecodeType(); + argumentNames[i] = parameter.getIdentifier(); + i++; + } + } + + //Methode generieren: + MethodGen method = new MethodGen(Constants.ACC_PUBLIC, this.getType().getBytecodeType(), argumentTypes , argumentNames, this.get_Method_Name(), parentClass.name, il, _cp); Block block = this.get_Block(); InstructionList blockInstructions = block.genByteCode(cg); @@ -759,7 +775,7 @@ public class Method extends Field implements IItemWithOffset, TypeInsertable } method.setMaxStack(); //Die Stack Größe automatisch berechnen lassen (erst nach dem alle Instructions angehängt wurden) - + method.setMaxLocals(); cg.addMethod(method.getMethod()); } diff --git a/src/de/dhbwstuttgart/syntaxtree/ParameterList.java b/src/de/dhbwstuttgart/syntaxtree/ParameterList.java index cdf632e18..acf0934b7 100755 --- a/src/de/dhbwstuttgart/syntaxtree/ParameterList.java +++ b/src/de/dhbwstuttgart/syntaxtree/ParameterList.java @@ -139,6 +139,10 @@ public class ParameterList extends SyntaxTreeNode implements Iterable getChildren() { return formalparameter; } + + public int size() { + return this.formalparameter.size(); + } } // ino.end diff --git a/src/de/dhbwstuttgart/syntaxtree/SourceFile.java b/src/de/dhbwstuttgart/syntaxtree/SourceFile.java index 1210078cb..43ddecc09 100755 --- a/src/de/dhbwstuttgart/syntaxtree/SourceFile.java +++ b/src/de/dhbwstuttgart/syntaxtree/SourceFile.java @@ -3,12 +3,15 @@ package de.dhbwstuttgart.syntaxtree; // ino.end // ino.module.SourceFile.8722.import +import java.io.IOException; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; + import de.dhbwstuttgart.typeinference.Menge; + import java.util.stream.Stream; import de.dhbwstuttgart.logger.Logger; @@ -29,6 +32,7 @@ import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.Type; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.type.Void; +import de.dhbwstuttgart.typeinference.ByteCodeResult; import de.dhbwstuttgart.typeinference.ConstraintsSet; import de.dhbwstuttgart.typeinference.FunN; import de.dhbwstuttgart.typeinference.FunNInterface; @@ -1368,7 +1372,7 @@ public class SourceFile } //basicAssumptions.addMethodIntersectionType(new CIntersectionType(constructor)); constructorMethod.parameterlist = paraList; - Constructor constructor = new Constructor(constructorMethod); + Constructor constructor = new Constructor(constructorMethod, parentClass); constructor.parserPostProcessing(parentClass); parentClass.addField(constructor); } @@ -1825,5 +1829,17 @@ public class SourceFile return 0; } + /** + * Bisher wird nur der Bytecode der Klassen generiert. Nicht der Interfaces. + * @return + */ + public Collection generateBytecode() { + Menge ret = new Menge<>(); + for(Class cl : this.KlassenVektor){ + ret.add(cl.genByteCode()); + } + return ret; + } + } // ino.end diff --git a/src/de/dhbwstuttgart/syntaxtree/statement/IntLiteral.java b/src/de/dhbwstuttgart/syntaxtree/statement/IntLiteral.java index 9c37c19a4..7d672ca48 100755 --- a/src/de/dhbwstuttgart/syntaxtree/statement/IntLiteral.java +++ b/src/de/dhbwstuttgart/syntaxtree/statement/IntLiteral.java @@ -4,10 +4,14 @@ package de.dhbwstuttgart.syntaxtree.statement; // ino.module.IntLiteral.8635.import import java.util.Hashtable; +import org.apache.bcel.Constants; import org.apache.bcel.generic.BIPUSH; import org.apache.bcel.generic.ClassGen; import org.apache.bcel.generic.InstructionFactory; +import org.apache.bcel.generic.InstructionHandle; import org.apache.bcel.generic.InstructionList; +import org.apache.bcel.generic.ObjectType; +import org.apache.bcel.generic.PUSH; import de.dhbwstuttgart.typeinference.Menge; import de.dhbwstuttgart.logger.Logger; @@ -137,8 +141,14 @@ public class IntLiteral extends Literal public InstructionList genByteCode(ClassGen cg) { InstructionFactory _factory = new InstructionFactory(cg, cg.getConstantPool()); InstructionList il = new InstructionList(); - il.append(new BIPUSH(new Integer(get_Int()).byteValue())); - return il; + + /* + * Der jetzige Compiler kann keine primitiven Typen. Ein int-Literal ist daher eine Instanz von java.lang.Integer + */ + il.append(new PUSH(cg.getConstantPool(), this.get_Int())); + il.append(_factory.createInvoke("java.lang.Integer", "valueOf", new ObjectType("java.lang.Integer"), new org.apache.bcel.generic.Type[] { org.apache.bcel.generic.Type.INT }, Constants.INVOKESTATIC)); + + return il; } } // ino.end diff --git a/src/de/dhbwstuttgart/syntaxtree/statement/MethodCall.java b/src/de/dhbwstuttgart/syntaxtree/statement/MethodCall.java index 1ea8c297f..3fffb2cf9 100755 --- a/src/de/dhbwstuttgart/syntaxtree/statement/MethodCall.java +++ b/src/de/dhbwstuttgart/syntaxtree/statement/MethodCall.java @@ -308,7 +308,8 @@ public class MethodCall extends Expr @Override public InstructionList genByteCode(ClassGen _cg) { - // TODO Auto-generated method stub + //Herausfinden, ob eine Methode oder ein Interface aufgerufen wird: + //this.receiver.get_Expr().getType() } diff --git a/src/de/dhbwstuttgart/syntaxtree/statement/Return.java b/src/de/dhbwstuttgart/syntaxtree/statement/Return.java index ad3907e07..21aca1781 100755 --- a/src/de/dhbwstuttgart/syntaxtree/statement/Return.java +++ b/src/de/dhbwstuttgart/syntaxtree/statement/Return.java @@ -138,10 +138,7 @@ public class Return extends Statement InstructionFactory _factory = new InstructionFactory(cg, cg.getConstantPool()); - //Stimmt das VOID hier eigentlich? --> Wie wäre es mit getReturnType o.ä.? + evtl. von Type zu bcelType casten? - il.append(_factory.createReturn(org.apache.bcel.generic.Type.VOID)); - - + il.append(_factory.createReturn(retexpr.getType().getBytecodeType())); return il; } diff --git a/test/bytecode/AssignTest.java b/test/bytecode/AssignTest.java index 415fb2a8d..232564dfd 100644 --- a/test/bytecode/AssignTest.java +++ b/test/bytecode/AssignTest.java @@ -20,26 +20,15 @@ import de.dhbwstuttgart.typeinference.Menge; import de.dhbwstuttgart.typeinference.TypeinferenceResultSet; import de.dhbwstuttgart.typeinference.typedeployment.TypeInsertSet; -public class Assign { +public class AssignTest { public final static String rootDirectory = System.getProperty("user.dir")+"/test/bytecode/"; public final static String testFile = "Assign.jav"; - public final static String outputFile = "AssignTest.class"; + public final static String outputFile = "Assign.class"; @Test public void test() { - LoggerConfiguration logConfig = new LoggerConfiguration().setOutput(Section.PARSER, System.out); - MyCompilerAPI compiler = MyCompiler.getAPI(logConfig); - try { - compiler.parse(new File(rootDirectory + testFile)); - compiler.typeReconstruction(); - ByteCodeResult bytecode = compiler.generateBytecode(); - System.out.println(bytecode); - bytecode.getByteCode().getJavaClass().dump(new File(rootDirectory + outputFile)); - } catch (IOException | yyException e) { - e.printStackTrace(); - TestCase.fail(); - } + SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile); } } diff --git a/test/bytecode/BoolLitTest.java b/test/bytecode/BoolLitTest.java index ef7b0fc33..75bd41ed4 100644 --- a/test/bytecode/BoolLitTest.java +++ b/test/bytecode/BoolLitTest.java @@ -28,18 +28,7 @@ public class BoolLitTest { @Test public void test() { - LoggerConfiguration logConfig = new LoggerConfiguration().setOutput(Section.PARSER, System.out); - MyCompilerAPI compiler = MyCompiler.getAPI(logConfig); - try { - compiler.parse(new File(rootDirectory + testFile)); - compiler.typeReconstruction(); - ByteCodeResult bytecode = compiler.generateBytecode(); - System.out.println(bytecode); - bytecode.getByteCode().getJavaClass().dump(new File(rootDirectory + outputFile)); - } catch (IOException | yyException e) { - e.printStackTrace(); - TestCase.fail(); - } + SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile); } } diff --git a/test/bytecode/CharLitTest.java b/test/bytecode/CharLitTest.java index add8b515b..60f2c4d5a 100644 --- a/test/bytecode/CharLitTest.java +++ b/test/bytecode/CharLitTest.java @@ -28,18 +28,7 @@ public class CharLitTest { @Test public void test() { - LoggerConfiguration logConfig = new LoggerConfiguration().setOutput(Section.PARSER, System.out); - MyCompilerAPI compiler = MyCompiler.getAPI(logConfig); - try { - compiler.parse(new File(rootDirectory + testFile)); - compiler.typeReconstruction(); - ByteCodeResult bytecode = compiler.generateBytecode(); - System.out.println(bytecode); - bytecode.getByteCode().getJavaClass().dump(new File(rootDirectory + outputFile)); - } catch (IOException | yyException e) { - e.printStackTrace(); - TestCase.fail(); - } + SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile); } } diff --git a/test/bytecode/EmptyClassTest.java b/test/bytecode/EmptyClassTest.java index 20aa33493..de7d900a2 100644 --- a/test/bytecode/EmptyClassTest.java +++ b/test/bytecode/EmptyClassTest.java @@ -28,18 +28,7 @@ public class EmptyClassTest { @Test public void test() { - LoggerConfiguration logConfig = new LoggerConfiguration().setOutput(Section.PARSER, System.out); - MyCompilerAPI compiler = MyCompiler.getAPI(logConfig); - try { - compiler.parse(new File(rootDirectory + testFile)); - compiler.typeReconstruction(); - ByteCodeResult bytecode = compiler.generateBytecode(); - System.out.println(bytecode); - bytecode.getByteCode().getJavaClass().dump(new File(rootDirectory + outputFile)); - } catch (IOException | yyException e) { - e.printStackTrace(); - TestCase.fail(); - } + SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile); } } diff --git a/test/bytecode/MethodCall.jav b/test/bytecode/MethodCall.jav new file mode 100644 index 000000000..cdedd45a7 --- /dev/null +++ b/test/bytecode/MethodCall.jav @@ -0,0 +1,9 @@ +class Assign{ + +void method() { +method(); +} + +void method2(){} + +} \ No newline at end of file diff --git a/test/bytecode/MethodCallTest.java b/test/bytecode/MethodCallTest.java new file mode 100644 index 000000000..96d23eee0 --- /dev/null +++ b/test/bytecode/MethodCallTest.java @@ -0,0 +1,34 @@ +package bytecode; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.junit.Test; + +import plugindevelopment.TypeInsertTester; +import de.dhbwstuttgart.core.MyCompiler; +import de.dhbwstuttgart.core.MyCompilerAPI; +import de.dhbwstuttgart.logger.LoggerConfiguration; +import de.dhbwstuttgart.logger.Section; +import de.dhbwstuttgart.parser.JavaParser.yyException; +import de.dhbwstuttgart.typeinference.ByteCodeResult; +import de.dhbwstuttgart.typeinference.Menge; +import de.dhbwstuttgart.typeinference.TypeinferenceResultSet; +import de.dhbwstuttgart.typeinference.typedeployment.TypeInsertSet; + +public class MethodCallTest { + + public final static String rootDirectory = System.getProperty("user.dir")+"/test/bytecode/"; + public final static String testFile = "MethodCall.jav"; + public final static String outputFile = "MethodCall.class"; + + @Test + public void test() { + SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile); + } + +} diff --git a/test/bytecode/Return.jav b/test/bytecode/Return.jav index 08c297924..36976731e 100644 --- a/test/bytecode/Return.jav +++ b/test/bytecode/Return.jav @@ -1,10 +1,7 @@ -class Assign{ +class Return{ -method() {a; - a = 20; - b; - b=59; - return a + b; +Integer method() { + return 5; } diff --git a/test/bytecode/ReturnTest.java b/test/bytecode/ReturnTest.java index 2d7c48037..a7179e11e 100644 --- a/test/bytecode/ReturnTest.java +++ b/test/bytecode/ReturnTest.java @@ -20,26 +20,15 @@ import de.dhbwstuttgart.typeinference.Menge; import de.dhbwstuttgart.typeinference.TypeinferenceResultSet; import de.dhbwstuttgart.typeinference.typedeployment.TypeInsertSet; -public class Return { +public class ReturnTest { public final static String rootDirectory = System.getProperty("user.dir")+"/test/bytecode/"; - public final static String testFile = "Assign.jav"; - public final static String outputFile = "Assign.class"; + public final static String testFile = "Return.jav"; + public final static String outputFile = "Return.class"; @Test public void test() { - LoggerConfiguration logConfig = new LoggerConfiguration().setOutput(Section.PARSER, System.out); - MyCompilerAPI compiler = MyCompiler.getAPI(logConfig); - try { - compiler.parse(new File(rootDirectory + testFile)); - compiler.typeReconstruction(); - ByteCodeResult bytecode = compiler.generateBytecode(); - System.out.println(bytecode); - bytecode.getByteCode().getJavaClass().dump(new File(rootDirectory + outputFile)); - } catch (IOException | yyException e) { - e.printStackTrace(); - TestCase.fail(); - } + SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile); } } diff --git a/test/bytecode/SingleClassTester.java b/test/bytecode/SingleClassTester.java new file mode 100644 index 000000000..f8a854633 --- /dev/null +++ b/test/bytecode/SingleClassTester.java @@ -0,0 +1,32 @@ +package bytecode; + +import java.io.File; +import java.io.IOException; + +import junit.framework.TestCase; +import de.dhbwstuttgart.core.MyCompiler; +import de.dhbwstuttgart.core.MyCompilerAPI; +import de.dhbwstuttgart.logger.LoggerConfiguration; +import de.dhbwstuttgart.logger.Section; +import de.dhbwstuttgart.parser.JavaParser.yyException; +import de.dhbwstuttgart.typeinference.ByteCodeResult; +import de.dhbwstuttgart.typeinference.Menge; + +public class SingleClassTester { + + public static void compileToBytecode(String inputFile, String outputFile){ + LoggerConfiguration logConfig = new LoggerConfiguration().setOutput(Section.PARSER, System.out); + MyCompilerAPI compiler = MyCompiler.getAPI(logConfig); + try { + compiler.parse(new File(inputFile)); + compiler.typeReconstruction(); + Menge bytecode = compiler.generateBytecode(); + System.out.println(bytecode); + bytecode.firstElement().getByteCode().getJavaClass().dump(new File(outputFile)); + } catch (IOException | yyException e) { + e.printStackTrace(); + TestCase.fail(); + } + } + +} diff --git a/test/bytecode/Test.java b/test/bytecode/Test.java index 2ff65c639..51e03e302 100644 --- a/test/bytecode/Test.java +++ b/test/bytecode/Test.java @@ -4,7 +4,7 @@ class Test{ public static void main(String[] args){ new EmptyClass(); - new AssignTest(); - + new Assign(); + System.out.println(new Return().method()); } }