From 4c213eb3cfebdecfbed5fc088d8208eaae592e5b Mon Sep 17 00:00:00 2001 From: Fayez Abu Alia Date: Thu, 5 Oct 2017 18:25:52 +0200 Subject: [PATCH] generate bytecode --- .../dhbwstuttgart/bytecode/BytecodeGen.java | 82 +++----- .../bytecode/BytecodeGenMethod.java | 198 ++++++++++++++---- src/de/dhbwstuttgart/bytecode/Descriptor.java | 54 +++++ 3 files changed, 239 insertions(+), 95 deletions(-) create mode 100644 src/de/dhbwstuttgart/bytecode/Descriptor.java diff --git a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java index 4919918b..6f0ac91e 100644 --- a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -9,7 +9,6 @@ import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; import de.dhbwstuttgart.syntaxtree.*; @@ -54,13 +53,17 @@ public class BytecodeGen implements ASTVisitor { // String methDesc; String type; + + String className; + // stores parameter, local vars and the next index on the local variable table, which use for aload_i, astore_i,... - HashMap paramsAndLocals = new HashMap<>(); + HashMap paramsAndLocals;// = new HashMap<>(); byte[] bytecode; HashMap classFiles; public BytecodeGen(HashMap classFiles) { this.classFiles = classFiles; + paramsAndLocals = new HashMap<>(); } @Override @@ -83,11 +86,15 @@ public class BytecodeGen implements ASTVisitor { } @Override public void visit(ClassOrInterface classOrInterface) { + className = classOrInterface.getClassName().toString(); // access flages?? - cw.visit(Opcodes.V1_8, classOrInterface.getModifiers(), classOrInterface.getClassName().toString() + cw.visit(Opcodes.V1_8, classOrInterface.getModifiers()+Opcodes.ACC_SUPER, classOrInterface.getClassName().toString() , null, classOrInterface.getSuperClass().toString(), null); + // for each field in the class for(Field f : classOrInterface.getFieldDecl()) { + System.out.println("get Fields"); + System.out.println(f.getName()); f.accept(this); } @@ -103,69 +110,30 @@ public class BytecodeGen implements ASTVisitor { @Override public void visit(Constructor field) { - String methDesc = getConsDesc(field); - MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", methDesc, null, null); + Descriptor desc = new Descriptor(field); + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", desc.getDesc(), null, null); mv.visitCode(); - - BytecodeGenMethod gen = new BytecodeGenMethod(field, mv,paramsAndLocals,true); + System.out.println("-----Constructor-----"); + BytecodeGenMethod gen = new BytecodeGenMethod(className,field, mv,paramsAndLocals,desc.getDesc(),cw); mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(0, 0); mv.visitEnd(); } - - private String getConsDesc(Constructor field) { - String methDesc; - methDesc = "("; - field.getParameterList().accept(this); - Iterator itr = field.getParameterList().iterator(); - while(itr.hasNext()) { - FormalParameter fp = itr.next(); - methDesc = methDesc + "L"+fp.getType().toString() + ";"; - } - methDesc = methDesc + ")V"; - return methDesc; - } @Override public void visit(Method method) { -// ParameterList pl = method.getParameterList(); - String methDesc = getMethDesc(method); -// methDesc = "("; -// method.getParameterList().accept(this); -// methDesc = methDesc + ")" + method.getReturnType().toString(); - - // create method descriptor (p1,p2,...)RT -// String methDesc = "("; - -// Iterator itr = pl.iterator(); -// while(itr.hasNext()) { -// FormalParameter fp = itr.next(); -//// fp.getType().accept(this); -// methDesc = methDesc + "L"+fp.getType().toString() + ";"; -// i++; -// } -// methDesc = methDesc + ")" + method.getReturnType().toString(); - - MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, method.getName(), methDesc, null, null); + method.getParameterList().accept(this); + Descriptor methDesc = new Descriptor(method); + System.out.println("-----Method-----"); + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, method.getName(), methDesc.getDesc(), null, null); mv.visitCode(); - BytecodeGenMethod gen = new BytecodeGenMethod(method, mv,paramsAndLocals,false); - + BytecodeGenMethod gen = new BytecodeGenMethod(className,method, mv,paramsAndLocals,methDesc.getDesc(),cw); + mv.visitMaxs(0, 0); + mv.visitEnd(); } - private String getMethDesc(Method method) { - String methDesc; - methDesc = "("; - method.getParameterList().accept(this); - Iterator itr = method.getParameterList().iterator(); - while(itr.hasNext()) { - FormalParameter fp = itr.next(); - methDesc = methDesc + "L"+fp.getType().toString() + ";"; - } - methDesc = methDesc + ")" + method.getReturnType().toString(); - return methDesc; - } - @Override public void visit(ParameterList formalParameters) { Iterator itr = formalParameters.iterator(); @@ -215,13 +183,17 @@ public class BytecodeGen implements ASTVisitor { // ?? @Override public void visit(FieldVar fieldVar) { + System.out.println("in fieldvar"); // cw.newField(fieldVar.receiver.toString(), fieldVar.fieldVarName.toString(), fieldVar.getType().toString()); + FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, fieldVar.fieldVarName, "L"+fieldVar.getType()+";", null, null); + fv.visitEnd(); } // access flages?? modifiers @Override public void visit(Field field) { - FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, field.getName(), "L"+field.getType()+";", null, null); + System.out.println("in field"); + FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, field.getName(), "L"+field.getType().toString().replace(".", "/")+";", null, null); fv.visitEnd(); } diff --git a/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java index 8a1d1cb4..c65e691c 100644 --- a/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java +++ b/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java @@ -1,9 +1,18 @@ package de.dhbwstuttgart.bytecode; +import java.io.PrintStream; +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.security.GeneralSecurityException; import java.util.HashMap; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; import de.dhbwstuttgart.syntaxtree.Method; @@ -16,6 +25,7 @@ import de.dhbwstuttgart.syntaxtree.statement.Block; import de.dhbwstuttgart.syntaxtree.statement.CastExpr; import de.dhbwstuttgart.syntaxtree.statement.DoStmt; import de.dhbwstuttgart.syntaxtree.statement.EmptyStmt; +import de.dhbwstuttgart.syntaxtree.statement.Expression; import de.dhbwstuttgart.syntaxtree.statement.FieldVar; import de.dhbwstuttgart.syntaxtree.statement.ForStmt; import de.dhbwstuttgart.syntaxtree.statement.IfStmt; @@ -38,31 +48,63 @@ import de.dhbwstuttgart.syntaxtree.statement.UnaryPlus; import de.dhbwstuttgart.syntaxtree.statement.WhileStmt; import de.dhbwstuttgart.syntaxtree.statement.literal.Literal; import de.dhbwstuttgart.syntaxtree.statement.literal.Null; +import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; public class BytecodeGenMethod implements StatementVisitor{ private Method m; private MethodVisitor mv; private HashMap paramsAndLocals = new HashMap<>(); + private String desc; + private String className; + private int lamCounter; + private ClassWriter cw; - public BytecodeGenMethod(Method m, MethodVisitor mv, HashMap paramsAndLocals, - boolean isConstructor) { - if(isConstructor) { + //for tests ** + private String fieldName; + private String fieldDesc; + private Expression rightSideTemp; + private String where; + + public BytecodeGenMethod(String className, Method m, MethodVisitor mv, HashMap paramsAndLocals, + String desc, ClassWriter cw) { -// mv.visitVarInsn(Opcodes.ALOAD, 0); -// mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V"); - } + this.where = "NORMAL METHOD"; + + this.className = className; this.m = m; this.mv = mv; this.paramsAndLocals = paramsAndLocals; + this.desc = desc; + this.cw = cw; + this.lamCounter = -1; + this.m.block.accept(this); } + public BytecodeGenMethod(LambdaExpression lambdaExpression, MethodVisitor mv, + HashMap paramsAndLocals, String desc) { + System.out.println("++++++IN LAMBDA -------"); + + this.where = "&&&&&&&& LAMBDA METHOD"; + + this.mv = mv; + this.paramsAndLocals = paramsAndLocals; + this.desc = desc; + + this.lamCounter = -1; + + lambdaExpression.methodBody.accept(this); + } + @Override public void visit(Block block) { for(Statement stmt : block.getStatements()) { + System.out.println(where); + System.out.println("Stmt : " + stmt.toString()); stmt.accept(this); + System.out.println("--------------------------\n"); } } @@ -70,39 +112,73 @@ public class BytecodeGenMethod implements StatementVisitor{ public void visit(SuperCall superCall) { superCall.receiver.accept(this); superCall.arglist.accept(this); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", superCall.name, "()V"); +// mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", superCall.name, desc,false); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), superCall.name, desc,false); } // ?? @Override public void visit(LocalVar localVar) { - + System.out.println("in Local Var"); } // ?? @Override public void visit(LocalVarDecl localVarDecl) { - // TODO Auto-generated method stub - Integer i; - +// Integer i; + paramsAndLocals.put(localVarDecl.getName(), paramsAndLocals.size()+1); + System.out.println("In localVarDecl"); } - // int c = 5;??? + @Override public void visit(Assign assign) { - assign.rightSide.accept(this); -// int index = paramsAndLocals.get(assign.lefSide.getName()); -// mv.visitVarInsn(Opcodes.ASTORE, index); + System.out.println("Assign : \nright = "+assign.rightSide + "\nLeft = " + assign.lefSide); + + if(assign.lefSide.getClass().equals(AssignToField.class)) { + // load_0, ldc or .. then putfield + this.rightSideTemp = assign.rightSide; + assign.lefSide.accept(this); + }else { + assign.rightSide.accept(this); + assign.lefSide.accept(this); + } + + + } @Override public void visit(Binary binary) { - // TODO Auto-generated method stub - + System.out.println("++ In Binary: "); } @Override public void visit(LambdaExpression lambdaExpression) { - // TODO Auto-generated method stub + System.out.println("\n++ In Lambda: "); + this.lamCounter++; + //Call site, which, when invoked, returns an instance of the functional interface to which + //the lambda is being converted + MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, + MethodType.class, MethodType.class, MethodHandle.class, MethodType.class); + + Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", + "metafactory", mt.toMethodDescriptorString(), false); + String methodName = "lambda$new$" + this.lamCounter; + // Type erasure + Type arg1 = Type.getMethodType("()V"); + // real Type + Type arg3 = Type.getMethodType("()V"); + Handle arg2 = new Handle(Opcodes.H_INVOKESTATIC, this.className, methodName, + arg3.toString(),false); + mv.visitInvokeDynamicInsn("run", "()Ljava/lang/Runnable;", bootstrap, + arg1, arg2,arg3); + + MethodVisitor mvLambdaBody = cw.visitMethod(Opcodes.ACC_PRIVATE+ Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC, + methodName, arg3.toString(), null, null); +// new BytecodeGenLambda(lambdaExpression, mvLambdaBody); + new BytecodeGenMethod(lambdaExpression, mvLambdaBody, new HashMap<>(), arg3.toString()); + mvLambdaBody.visitMaxs(0, 0); + mvLambdaBody.visitEnd(); } @Override @@ -119,8 +195,19 @@ public class BytecodeGenMethod implements StatementVisitor{ @Override public void visit(FieldVar fieldVar) { - // TODO Auto-generated method stub + System.out.println("in fieldVar " + fieldVar.fieldVarName + " ** receiver: "+fieldVar.receiver); + fieldName = fieldVar.fieldVarName; + fieldDesc = fieldVar.getType().toString(); + + fieldVar.receiver.accept(this); + // test (if) + if(!fieldVar.receiver.getClass().equals(StaticClassName.class)) { + mv.visitFieldInsn(Opcodes.GETFIELD,fieldVar.getType().toString(),fieldName ,fieldDesc); + } + +// mv.visitFieldInsn(Opcodes.GETSTATIC, fieldVar.receiver.getType().toString().replace(".", "/"), +// fieldVar.fieldVarName, fieldVar.getType().toString()); } @Override @@ -131,8 +218,7 @@ public class BytecodeGenMethod implements StatementVisitor{ @Override public void visit(IfStmt ifStmt) { - // TODO Auto-generated method stub - + System.out.println("++ IF-Statment: "); } @Override @@ -143,13 +229,38 @@ public class BytecodeGenMethod implements StatementVisitor{ @Override public void visit(MethodCall methodCall) { + System.out.println(" In Methodcall: (" +methodCall.name+")" ); + System.out.println(" Method-Receiver: "+methodCall.receiver.expr); + methodCall.receiver.accept(this); + methodCall.arglist.accept(this); + + Descriptor mDesc = new Descriptor(methodCall.arglist, methodCall.getType()); + + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, methodCall.receiver.expr.getType().toString(), + methodCall.name, mDesc.getDesc(), false); + // test + if(!methodCall.getType().toString().equals("V")) { + mv.visitInsn(Opcodes.POP); + } } @Override public void visit(NewClass methodCall) { - // TODO Auto-generated method stub + System.out.println("In NewClass: "); + System.out.println("name: " + methodCall.name + " *** " + "Receiver: " + methodCall.receiver); + mv.visitTypeInsn(Opcodes.NEW, methodCall.name.replace(".", "/")); + mv.visitInsn(Opcodes.DUP); + // creates Descriptor + methodCall.arglist.accept(this); + String d = "("; + for(Expression e : methodCall.arglist.getArguments()) { + d = d + "L"+e.getType().toString().replace(".", "/") + ";"; + } + d += ")V"; + + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, methodCall.name.replace(".", "/"), "", d, false); } @Override @@ -160,13 +271,14 @@ public class BytecodeGenMethod implements StatementVisitor{ @Override public void visit(Receiver receiver) { + System.out.println(" in Receiver"); + System.out.println(" expr : " + receiver.expr); receiver.expr.accept(this); } @Override public void visit(Return aReturn) { - // TODO Auto-generated method stub - + mv.visitInsn(Opcodes.ARETURN); } @Override @@ -176,25 +288,27 @@ public class BytecodeGenMethod implements StatementVisitor{ @Override public void visit(StaticClassName staticClassName) { - // TODO Auto-generated method stub - + System.out.println("In StaticClassName: "); +// mv.visitMethodInsn(Opcodes.INVOKESTATIC, staticClassName.getType().toString().replace(".", "/"), +// staticClassName.toString(), staticClassName.getType().toString(), false); + mv.visitFieldInsn(Opcodes.GETSTATIC, staticClassName.getType().toString().replace(".", "/"), + fieldName, fieldDesc); } @Override public void visit(Super aSuper) { - // TODO Auto-generated method stub - + System.out.println(">> In Super: "); } @Override public void visit(This aThis) { + System.out.println("-> IN This"); mv.visitVarInsn(Opcodes.ALOAD, 0); } @Override public void visit(UnaryPlus unaryPlus) { - // TODO Auto-generated method stub - + System.out.println("++ In UnaryPlus: "); } @Override @@ -211,32 +325,36 @@ public class BytecodeGenMethod implements StatementVisitor{ @Override public void visit(Null aNull) { - // TODO Auto-generated method stub - + mv.visitInsn(Opcodes.ACONST_NULL); } @Override public void visit(Literal literal) { - // TODO Auto-generated method stub - + // value? + mv.visitLdcInsn(literal.getType().toString()); } @Override public void visit(ArgumentList argumentList) { - // TODO Auto-generated method stub - + for(Expression al : argumentList.getArguments()) { + al.accept(this); + } } @Override public void visit(AssignToField assignLeftSide) { - // TODO Auto-generated method stub - + // Loads the an object reference from the local variable + // array slot onto the top of the operand stack. + assignLeftSide.field.receiver.accept(this); + this.rightSideTemp.accept(this); + mv.visitFieldInsn(Opcodes.PUTFIELD, assignLeftSide.field.receiver.getType().toString(), + assignLeftSide.field.fieldVarName, assignLeftSide.field.getType().toString()); } @Override public void visit(AssignToLocal assignLeftSide) { - // TODO Auto-generated method stub - + paramsAndLocals.put(assignLeftSide.localVar.name, paramsAndLocals.size()+1); + mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.size()); } } diff --git a/src/de/dhbwstuttgart/bytecode/Descriptor.java b/src/de/dhbwstuttgart/bytecode/Descriptor.java new file mode 100644 index 00000000..41f7ab5d --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/Descriptor.java @@ -0,0 +1,54 @@ +package de.dhbwstuttgart.bytecode; + +import java.awt.List; +import java.util.Iterator; + +import de.dhbwstuttgart.syntaxtree.Constructor; +import de.dhbwstuttgart.syntaxtree.FormalParameter; +import de.dhbwstuttgart.syntaxtree.Method; +import de.dhbwstuttgart.syntaxtree.statement.ArgumentList; +import de.dhbwstuttgart.syntaxtree.statement.Expression; +import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; + +public class Descriptor { + String desc; + + public Descriptor(Method method) { + desc = "("; + Iterator itr = method.getParameterList().iterator(); + while(itr.hasNext()) { + FormalParameter fp = itr.next(); + desc = desc + "L"+fp.getType().toString().replace(".", "/") + ";"; + } + if(method.getReturnType().toString().equals("void")){ + desc = desc + ")V"; + }else { + desc = desc + ")" + "L"+method.getReturnType().toString().replace(".", "/")+";"; + } + + } + + public Descriptor(Constructor constructor) { + desc = "("; + Iterator itr = constructor.getParameterList().iterator(); + while(itr.hasNext()) { + FormalParameter fp = itr.next(); + desc = desc + "L"+fp.getType().toString().replace(".", "/") + ";"; + } + desc = desc + ")V"; + } + + public Descriptor(ArgumentList argList, RefTypeOrTPHOrWildcardOrGeneric returnType) { + desc = "("; + for(Expression e : argList.getArguments()) { + desc = desc + "L"+e.getType().toString().replace(".", "/") + ";"; + } + desc = desc + ")"+returnType.toString(); + + } + + public String getDesc() { + return this.desc; + } + +}