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; import de.dhbwstuttgart.syntaxtree.StatementVisitor; import de.dhbwstuttgart.syntaxtree.statement.ArgumentList; import de.dhbwstuttgart.syntaxtree.statement.Assign; import de.dhbwstuttgart.syntaxtree.statement.AssignToField; import de.dhbwstuttgart.syntaxtree.statement.Binary; 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; import de.dhbwstuttgart.syntaxtree.statement.InstanceOf; import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression; import de.dhbwstuttgart.syntaxtree.statement.LocalVar; import de.dhbwstuttgart.syntaxtree.statement.LocalVarDecl; import de.dhbwstuttgart.syntaxtree.statement.MethodCall; import de.dhbwstuttgart.syntaxtree.statement.NewArray; import de.dhbwstuttgart.syntaxtree.statement.NewClass; import de.dhbwstuttgart.syntaxtree.statement.Receiver; import de.dhbwstuttgart.syntaxtree.statement.Return; import de.dhbwstuttgart.syntaxtree.statement.ReturnVoid; import de.dhbwstuttgart.syntaxtree.statement.Statement; import de.dhbwstuttgart.syntaxtree.statement.StaticClassName; import de.dhbwstuttgart.syntaxtree.statement.Super; import de.dhbwstuttgart.syntaxtree.statement.SuperCall; import de.dhbwstuttgart.syntaxtree.statement.This; 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; //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) { 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"); } } @Override public void visit(SuperCall superCall) { superCall.receiver.accept(this); superCall.arglist.accept(this); // 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) { // Integer i; paramsAndLocals.put(localVarDecl.getName(), paramsAndLocals.size()+1); System.out.println("In localVarDecl"); } @Override public void visit(Assign assign) { 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) { System.out.println("++ In Binary: "); } @Override public void visit(LambdaExpression lambdaExpression) { 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 public void visit(CastExpr castExpr) { // TODO Auto-generated method stub } @Override public void visit(EmptyStmt emptyStmt) { // TODO Auto-generated method stub } @Override public void visit(FieldVar fieldVar) { 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 public void visit(ForStmt forStmt) { // TODO Auto-generated method stub } @Override public void visit(IfStmt ifStmt) { System.out.println("++ IF-Statment: "); } @Override public void visit(InstanceOf instanceOf) { // TODO Auto-generated method stub } @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) { 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 public void visit(NewArray newArray) { // TODO Auto-generated method stub } @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) { mv.visitInsn(Opcodes.ARETURN); } @Override public void visit(ReturnVoid aReturn) { mv.visitInsn(Opcodes.RETURN); } @Override public void visit(StaticClassName staticClassName) { 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) { 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) { System.out.println("++ In UnaryPlus: "); } @Override public void visit(WhileStmt whileStmt) { // TODO Auto-generated method stub } @Override public void visit(DoStmt whileStmt) { // TODO Auto-generated method stub } @Override public void visit(Null aNull) { mv.visitInsn(Opcodes.ACONST_NULL); } @Override public void visit(Literal literal) { // value? mv.visitLdcInsn(literal.getType().toString()); } @Override public void visit(ArgumentList argumentList) { for(Expression al : argumentList.getArguments()) { al.accept(this); } } @Override public void visit(AssignToField assignLeftSide) { // 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) { paramsAndLocals.put(assignLeftSide.localVar.name, paramsAndLocals.size()+1); mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.size()); } }