diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java index b2699cd4..46caa52b 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java @@ -1,9 +1,5 @@ package de.dhbwstuttgart.bytecode; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -14,11 +10,10 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; +import de.dhbwstuttgart.bytecode.utilities.*; import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.statement.BinaryExpr.Operator; @@ -30,28 +25,15 @@ import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; -import org.objectweb.asm.signature.SignatureVisitor; -import org.objectweb.asm.signature.SignatureWriter; import de.dhbwstuttgart.bytecode.Exception.NotInCurrentPackageException; import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString; import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor; -import de.dhbwstuttgart.bytecode.signature.Signature; -import de.dhbwstuttgart.bytecode.signature.TypeToSignature; -import de.dhbwstuttgart.bytecode.utilities.KindOfLambda; -import de.dhbwstuttgart.bytecode.utilities.Lambda; -import de.dhbwstuttgart.bytecode.utilities.MethodCallHelper; -import de.dhbwstuttgart.bytecode.utilities.MethodFromMethodCall; -import de.dhbwstuttgart.bytecode.utilities.Resolver; -import de.dhbwstuttgart.bytecode.utilities.SamMethod; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; -import de.dhbwstuttgart.syntaxtree.AbstractASTWalker; -import de.dhbwstuttgart.syntaxtree.ClassOrInterface; import de.dhbwstuttgart.syntaxtree.FormalParameter; import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.SourceFile; import de.dhbwstuttgart.syntaxtree.StatementVisitor; -import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.typeinference.result.ResultSet; @@ -64,7 +46,7 @@ public class BytecodeGenMethod implements StatementVisitor { private MethodVisitor mv; private HashMap paramsAndLocals = new HashMap<>(); private String className; - private int lamCounter = -1; + private int lamCounter; private ClassWriter cw; private ResultSet resultSet; private boolean isInterface; @@ -114,6 +96,7 @@ public class BytecodeGenMethod implements StatementVisitor { this.classFiles = classFiles; this.sf = sf; this.path = path; + this.lamCounter = -1; this.constructorPos = constructorPos; if(block != null) this.blockFieldInit = block; @@ -140,16 +123,17 @@ public class BytecodeGenMethod implements StatementVisitor { this.classFiles = classFiles; this.sf = sf; this.path = path; - + this.lamCounter = -1; if (!isInterface) this.m.block.accept(this); } - public BytecodeGenMethod(LambdaExpression lambdaExpression, ArrayList usedVars, ResultSet resultSet, MethodVisitor mv, + public BytecodeGenMethod(String className, ClassWriter cw, LambdaExpression lambdaExpression, ArrayList usedVars, ResultSet resultSet, MethodVisitor mv, int indexOfFirstParamLam, boolean isInterface, HashMap classFiles, String path, int lamCounter, SourceFile sf,HashMap genericsAndBoundsMethod, HashMap genericsAndBounds) { - + this.className = className; + this.cw = cw; this.resultSet = resultSet; this.resolver = new Resolver(resultSet); this.mv = mv; @@ -192,7 +176,7 @@ public class BytecodeGenMethod implements StatementVisitor { stmt.accept(this); if(stmt instanceof MethodCall) { String ret = resolver.getResolvedType(((MethodCall) stmt).getType()); - if(!ret.equals("void")) + if(!ret.equals(CONSTANTS.VOID)) mv.visitInsn(Opcodes.POP); } } @@ -267,7 +251,7 @@ public class BytecodeGenMethod implements StatementVisitor { System.out.println("ASSIGN TYPE R: " + resolver.getResolvedType(assign.rightSide.getType())); String typeOfRightSide = resolver.getResolvedType(assign.rightSide.getType()); - if(typeOfRightSide.contains("<")) { + if(typeOfRightSide.contains(CONSTANTS.ANGLEBRACKET)) { mv.visitTypeInsn(Opcodes.CHECKCAST, typeOfRightSide.substring(0, typeOfRightSide.indexOf('<'))); } assign.lefSide.accept(this); @@ -380,11 +364,11 @@ public class BytecodeGenMethod implements StatementVisitor { private void doCast(String sourceType, String dest) { switch (dest) { - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: mv.visitInsn(Opcodes.I2L); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: if (sourceType.equals(Type.getInternalName(Long.class))) { mv.visitInsn(Opcodes.L2D); } else if (sourceType.equals(Type.getInternalName(Float.class))) { @@ -394,7 +378,7 @@ public class BytecodeGenMethod implements StatementVisitor { } break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: if (sourceType.equals(Type.getInternalName(Long.class))) { mv.visitInsn(Opcodes.L2F); } else { @@ -402,7 +386,7 @@ public class BytecodeGenMethod implements StatementVisitor { } break; // braucht man eigentlich nicht, muss getestet werden - case "java/lang/String": + case CONSTANTS.REFTYPE_STRING: if (sourceType.equals(Type.getInternalName(Double.class))) { mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(String.class), "valueOf", "(D)Ljava/lang/String;", false); @@ -425,15 +409,15 @@ public class BytecodeGenMethod implements StatementVisitor { private void doVisitRelOpInsn(Operator op, String typeOfBinary, Label branchLabel, Label endLabel) { System.out.println("TypeOfBinary: " + typeOfBinary); switch (typeOfBinary) { - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: mv.visitInsn(Opcodes.LCMP); doVisitIfInRelOp(op, branchLabel, endLabel); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: mv.visitInsn(Opcodes.DCMPG); doVisitIfInRelOp(op, branchLabel, endLabel); break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: mv.visitInsn(Opcodes.FCMPG); doVisitIfInRelOp(op, branchLabel, endLabel); break; @@ -497,13 +481,13 @@ public class BytecodeGenMethod implements StatementVisitor { private void doVisitModOpInsn(String typeOfBinary) { switch (typeOfBinary) { - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: mv.visitInsn(Opcodes.LREM); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: mv.visitInsn(Opcodes.DREM); break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: mv.visitInsn(Opcodes.FREM); break; default: @@ -514,13 +498,13 @@ public class BytecodeGenMethod implements StatementVisitor { private void doVisitDivOpInsn(String typeOfBinary) { switch (typeOfBinary) { - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: mv.visitInsn(Opcodes.LDIV); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: mv.visitInsn(Opcodes.DDIV); break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: mv.visitInsn(Opcodes.FDIV); break; default: @@ -531,13 +515,13 @@ public class BytecodeGenMethod implements StatementVisitor { private void doVisitMulOpInsn(String typeOfBinary) { switch (typeOfBinary) { - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: mv.visitInsn(Opcodes.LMUL); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: mv.visitInsn(Opcodes.DMUL); break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: mv.visitInsn(Opcodes.FMUL); break; default: @@ -548,13 +532,13 @@ public class BytecodeGenMethod implements StatementVisitor { private void doVisitSubOpInsn(String typeOfBinary) { switch (typeOfBinary) { - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: mv.visitInsn(Opcodes.LSUB); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: mv.visitInsn(Opcodes.DSUB); break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: mv.visitInsn(Opcodes.FSUB); break; default: @@ -566,26 +550,26 @@ public class BytecodeGenMethod implements StatementVisitor { private void doVisitAddOpInsn(String typeOfBinary) { switch (typeOfBinary) { - case "java/lang/Byte": + case CONSTANTS.REFTYPE_BYTE: mv.visitInsn(Opcodes.IADD); break; - case "java/lang/Short": + case CONSTANTS.REFTYPE_SHORT: mv.visitInsn(Opcodes.IADD); break; - case "java/lang/Integer": + case CONSTANTS.REFTYPE_INTEGER: mv.visitInsn(Opcodes.IADD); break; - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: mv.visitInsn(Opcodes.LADD); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: mv.visitInsn(Opcodes.DADD); break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: mv.visitInsn(Opcodes.FADD); break; - case "java/lang/String": - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", + case CONSTANTS.REFTYPE_STRING: + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", CONSTANTS.TO_STRING, "()Ljava/lang/String;", false); break; default: @@ -596,17 +580,10 @@ public class BytecodeGenMethod implements StatementVisitor { @Override public void visit(LambdaExpression lambdaExpression) { this.lamCounter++; - - String typeErasure = "("; - Iterator itr = lambdaExpression.params.iterator(); - while (itr.hasNext()) { - itr.next(); - typeErasure += "L" + Type.getInternalName(Object.class) + ";"; - } - typeErasure += ")L" + Type.getInternalName(Object.class) + ";"; - - generateBCForFunN(lambdaExpression, typeErasure); + String typeErasure = createDescriptorWithTypeErasure(lambdaExpression); + + ByteCodeForFunNGenerator.generateBCForFunN(lambdaExpression, typeErasure,path); Lambda lam = new Lambda(lambdaExpression); @@ -619,7 +596,7 @@ public class BytecodeGenMethod implements StatementVisitor { Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory", mt.toMethodDescriptorString(), false); - String methodName = "lambda$new$" + this.lamCounter; + String desugaredMethodName = CONSTANTS.DESUGAREDMETHODNAME + this.lamCounter; // Für die Parameter-Typen und Return-Typ braucht man die Bounds (für die // Typlöschung) @@ -630,37 +607,22 @@ public class BytecodeGenMethod implements StatementVisitor { // real Type Type arg3 = Type.getMethodType(lamDesc); - int staticOrSpecial = 0; - int staticOrInstance = 0; - int indexOfFirstParamLam = 0; + int staticOrSpecial, staticOrInstance = 0, indexOfFirstParamLam = 0; + this.kindOfLambda = new KindOfLambda(lambdaExpression); if (kindOfLambda.isInstanceCapturingLambda()) { -// if(!kindOfLambda.getArgumentList().contains(BytecodeGen.THISTYPE)) -// kindOfLambda.getArgumentList().add(0, BytecodeGen.THISTYPE); mv.visitVarInsn(Opcodes.ALOAD, 0); - for(String v : kindOfLambda.getUsedVars()) { - mv.visitVarInsn(Opcodes.ALOAD, paramsAndLocals.get(v)); - } + loadUsedVarsInLambda(); staticOrSpecial = Opcodes.H_INVOKESPECIAL; indexOfFirstParamLam = 1; } else { staticOrSpecial = Opcodes.H_INVOKESTATIC; staticOrInstance = Opcodes.ACC_STATIC; } - String newDesc = "("; - int pos = 0; - if(kindOfLambda.isHasThis()) { - pos = 1; - } - - for(int i=pos;i usedVars = kindOfLambda.getUsedVars(); - new BytecodeGenMethod(lambdaExpression, usedVars,this.resultSet, mvLambdaBody, indexOfFirstParamLam, isInterface, + new BytecodeGenMethod(className, cw,lambdaExpression, usedVars,this.resultSet, mvLambdaBody, indexOfFirstParamLam, isInterface, classFiles,this.path, lamCounter, sf, genericsAndBoundsMethod, genericsAndBounds); @@ -684,49 +646,41 @@ public class BytecodeGenMethod implements StatementVisitor { // generateBCForFunN(lambdaExpression, typeErasure); } - private void generateBCForFunN(LambdaExpression lambdaExpression, String methDesc) { - ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + private String addUsedVarsToDesugaredMethodDescriptor(String lamDesc) { + String newDesc = "("; + int pos = 0; + if(kindOfLambda.isThisUsed()) { + pos = 1; + } - SignatureWriter methSig = new SignatureWriter(); + for(int i=pos;i itr = lambdaExpression.params.iterator(); while (itr.hasNext()) { - numberOfParams++; - // getBounds - paramVisitor.visitTypeVariable("T" + numberOfParams); itr.next(); - } - methSig.visitReturnType().visitTypeVariable("R"); - // ")"+lam.getReturn.getBounds - Signature sig = new Signature(numberOfParams); - String name = "Fun" + numberOfParams + "$$"; - classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(), - Type.getInternalName(Object.class), null); - MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc, - methSig.toString(), null); - mvApply.visitEnd(); - writeClassFile(classWriter.toByteArray(), name); - } - - public void writeClassFile(byte[] bytecode, String name) { - FileOutputStream output; - try { - System.out.println("generating " + name + ".class file..."); - output = new FileOutputStream( - new File(path + name + ".class")); - output.write(bytecode); - output.close(); - System.out.println(name + ".class file generated"); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + typeErasure += "L" + Type.getInternalName(Object.class) + ";"; } + typeErasure += ")L" + Type.getInternalName(Object.class) + ";"; + return typeErasure; } + + @Override public void visit(CastExpr castExpr) { @@ -802,8 +756,6 @@ public class BytecodeGenMethod implements StatementVisitor { MethodCallHelper helper = new MethodCallHelper(methodCall, sf, resultSet, path); - boolean toCreate = false; - ClassLoader cLoader = ClassLoader.getSystemClassLoader(); // This will be used if the class is not standard class (not in API) ClassLoader cLoader2; @@ -811,9 +763,7 @@ public class BytecodeGenMethod implements StatementVisitor { String methCallType = resultSet.resolveType(methodCall.getType()).resolvedType.acceptTV(new TypeToDescriptor()); String[] typesOfParams = getTypes(methodCall.arglist.getArguments()); try { - if (receiverName.contains("<")) { - clazz = clazz.substring(0, receiverName.indexOf("<")); - } + clazz = getRawClassName(receiverName, clazz); java.lang.reflect.Method[] methods = cLoader.loadClass(clazz).getMethods(); System.out.println("Methods of " + receiverName + " "); @@ -827,19 +777,12 @@ public class BytecodeGenMethod implements StatementVisitor { try { String superClazz = superClass.replace("/", "."); - if(superClass.contains("<")) { - superClazz = superClazz.substring(0, superClass.indexOf("<")); - } + superClazz = getRawClassName(superClass, superClazz); java.lang.reflect.Method[] methods = cLoader.loadClass(superClazz).getMethods(); System.out.println("Methods of " + superClass + " "); - - for(java.lang.reflect.Method m : methods) { - if(methodCall.name.equals(m.getName())) { - methodRefl = m; - break; - } - } - + + methodRefl = getMethod(methodCall.name, methodCall.arglist.getArguments().size(), methods); + break; } catch (Exception e3) { receiverName = superClass; @@ -854,7 +797,7 @@ public class BytecodeGenMethod implements StatementVisitor { } if(methodRefl == null) { - toCreate = !receiverName.equals(className) && helper.isInCurrPkg(clazz); + boolean toCreate = !receiverName.equals(className) && helper.isInCurrPkg(clazz); if(toCreate) { try { mDesc = helper.getDesc(clazz); @@ -862,8 +805,9 @@ public class BytecodeGenMethod implements StatementVisitor { e.printStackTrace(); } } else if(!helper.isInCurrPkg(clazz)){ - if(clazz.contains("$$")) { - mDesc = helper.generateBCForFunN(); + if(clazz.contains(CONSTANTS.$$)) { + mDesc = helper.getDescriptorOfApplyMethod(methCallType); + helper.generateBCForFunN(mDesc); // mDesc = helper.generateBCForFunN(methCallType,typesOfParams); }else { try { @@ -896,18 +840,10 @@ public class BytecodeGenMethod implements StatementVisitor { } else if(methodRefl != null) { System.out.println(methodCall.name + " -> Refl != null"); receiverRefl = methodRefl.getAnnotatedReceiverType().getType().toString(); - for(Parameter p:methodRefl.getParameters()) { - System.out.println(p.getName() + " und is Primitive = " + p.getType().isPrimitive()); - argListMethCall.add(p.getType().isPrimitive()); - } + getBoolListOfType(methodRefl, argListMethCall); System.out.println("Receiver = " + methodRefl.getAnnotatedReceiverType().getType().toString()); mDesc = getMethodDesc(methodRefl); - for (Expression al : methodCall.arglist.getArguments()) { - statement = new ArgumentExpr(al); - ArgumentVisitor argV = new ArgumentVisitor(argListMethCall,this); - al.accept(argV); - statement = null; - } + visitArgumentListOfMethodCallFromStandardAPI(methodCall, argListMethCall); } else { methodCall.arglist.accept(this); } @@ -916,27 +852,20 @@ public class BytecodeGenMethod implements StatementVisitor { // methodCall.arglist.accept(this); - - // is methodCall.receiver functional Interface)? - if (varsFunInterface.contains(methodCall.receiver.getType()) || (methodRefl!= null && receiverRefl.contains("interface")) || - receiverName.contains("$$")) { - mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, clazz.replace(".", "/"), methodCall.name, - mDesc, true); - } else { - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, clazz.replace(".", "/"), methodCall.name, - mDesc, isInterface); - } - - + visitInvokeInsn(methodCall, receiverName, methodRefl, clazz, mDesc, receiverRefl); + + if(methodRefl != null && !methodRefl.getReturnType().isPrimitive()) { if(methodRefl.getReturnType().equals(Object.class)) { helper.createCheckCast(methodCall,mv); } - if(isBinaryExp) { + /*if(isBinaryExp) { + doUnboxing(resolver.getResolvedType(methodCall.getType())); + }*/ + if(parentBinary || isBinaryExp) { doUnboxing(resolver.getResolvedType(methodCall.getType())); - } - } else if(receiverName.contains("$$") && !methCallType.equals(Type.getInternalName(Object.class))) { + } else if(receiverName.contains(CONSTANTS.$$) && !methCallType.equals(Type.getInternalName(Object.class))) { helper.createCheckCast(methodCall,mv); } System.out.println("ISParent Binary = "+isParentBinary +" -> " + parentBinary); @@ -947,18 +876,39 @@ public class BytecodeGenMethod implements StatementVisitor { } - - private String getDescForMethInCurrPkg(String name) { - // TODO Auto-generated method stub - return null; + private void getBoolListOfType(java.lang.reflect.Method methodRefl, List argListMethCall) { + for(Parameter p:methodRefl.getParameters()) { + System.out.println(p.getName() + " und is Primitive = " + p.getType().isPrimitive()); + argListMethCall.add(p.getType().isPrimitive()); + } } - private boolean isInCurrPkg(String superClass) { - for(ClassOrInterface cl : sf.KlassenVektor) { - if(superClass.equals(cl.getClassName().toString())) - return true; + private void visitArgumentListOfMethodCallFromStandardAPI(MethodCall methodCall, List argListMethCall) { + for (Expression al : methodCall.arglist.getArguments()) { + statement = new ArgumentExpr(al); + ArgumentVisitor argV = new ArgumentVisitor(argListMethCall,this); + al.accept(argV); + statement = null; } - return false; + } + + private void visitInvokeInsn(MethodCall methodCall, String receiverName, java.lang.reflect.Method methodRefl, String clazz, String mDesc, String receiverRefl) { + // is methodCall.receiver functional Interface)? + if (varsFunInterface.contains(methodCall.receiver.getType()) || (methodRefl!= null && receiverRefl.contains("interface")) || + receiverName.contains(CONSTANTS.$$)) { + mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, clazz.replace(".", "/"), methodCall.name, + mDesc, true); + } else { + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, clazz.replace(".", "/"), methodCall.name, + mDesc, isInterface); + } + } + + private String getRawClassName(String receiverName, String clazz) { + if (receiverName.contains(CONSTANTS.ANGLEBRACKET)) { + clazz = clazz.substring(0, receiverName.indexOf(CONSTANTS.ANGLEBRACKET)); + } + return clazz; } private String[] getTypes(List arguments) { @@ -1067,15 +1017,24 @@ public class BytecodeGenMethod implements StatementVisitor { mv.visitInsn(Opcodes.DUP); // creates Descriptor methodCall.arglist.accept(this); - String d = "("; - for (Expression e : methodCall.arglist.getArguments()) { - d = d + "L" + resolver.getResolvedType(e.getType()) + ";"; - } - d += ")V"; + String d = createDescriptorForInitMethod(methodCall); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, methodCall.name.replace(".", "/"), "", d, isInterface); } + private String createDescriptorForInitMethod(NewClass methodCall) { + String d = "("; + for (Expression e : methodCall.arglist.getArguments()) { + String type = resolver.getResolvedType(e.getType()); + if(type.contains("TPH ")){ + type = Type.getInternalName(Object.class); + } + d = d + "L" + type + ";"; + } + d += ")V"; + return d; + } + @Override public void visit(NewArray newArray) { // TODO Auto-generated method stub @@ -1136,13 +1095,13 @@ public class BytecodeGenMethod implements StatementVisitor { private void doVisitNegIns(String typeOfUnary) { switch (typeOfUnary) { - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: mv.visitInsn(Opcodes.LNEG); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: mv.visitInsn(Opcodes.DNEG); break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: mv.visitInsn(Opcodes.FNEG); break; default: @@ -1260,23 +1219,23 @@ public class BytecodeGenMethod implements StatementVisitor { case "java/lang/Boolean": mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false); break; - case "java/lang/Byte": - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false); + case CONSTANTS.REFTYPE_BYTE: + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CONSTANTS.REFTYPE_BYTE, "byteValue", "()B", false); break; - case "java/lang/Short": - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false); + case CONSTANTS.REFTYPE_SHORT: + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CONSTANTS.REFTYPE_SHORT, "shortValue", "()S", false); break; case "java/lang/Integer": mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); break; - case "java/lang/Long": - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false); + case CONSTANTS.REFTYPE_LONG: + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CONSTANTS.REFTYPE_LONG, "longValue", "()J", false); break; - case "java/lang/Float": - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false); + case CONSTANTS.REFTYPE_FLOAT: + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CONSTANTS.REFTYPE_FLOAT, "floatValue", "()F", false); break; - case "java/lang/Double": - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false); + case CONSTANTS.REFTYPE_DOUBLE: + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CONSTANTS.REFTYPE_DOUBLE, "doubleValue", "()D", false); break; case "java/lang/Character": break; @@ -1289,19 +1248,19 @@ public class BytecodeGenMethod implements StatementVisitor { private void loadValue(String type, Object value, boolean isOperator) { switch (type) { - case "java/lang/String": + case CONSTANTS.REFTYPE_STRING: mv.visitLdcInsn(String.valueOf(value)); break; case "java/lang/Boolean": visitBooleanLiteral((Boolean) value); break; - case "java/lang/Byte": + case CONSTANTS.REFTYPE_BYTE: if(value instanceof Double) visitByteLiteral(((Double) value).byteValue(), false); if(value instanceof Integer) visitByteLiteral(((Integer) value).byteValue(), false); break; - case "java/lang/Short": + case CONSTANTS.REFTYPE_SHORT: if(value instanceof Double) visitShortLiteral(((Double) value).shortValue(), false); if(value instanceof Integer) @@ -1315,19 +1274,19 @@ public class BytecodeGenMethod implements StatementVisitor { if(value instanceof Integer) visitIntegerLiteral(((Integer) value).intValue(), false); break; - case "java/lang/Long": + case CONSTANTS.REFTYPE_LONG: if(value instanceof Double) visitLongLiteral(((Double) value).longValue(), true); if(value instanceof Integer) visitLongLiteral(((Integer) value).longValue(), true); break; - case "java/lang/Float": + case CONSTANTS.REFTYPE_FLOAT: if(value instanceof Double) visitFloatLiteral(((Double) value).floatValue()); if(value instanceof Integer) visitFloatLiteral(((Integer) value).floatValue()); break; - case "java/lang/Double": + case CONSTANTS.REFTYPE_DOUBLE: if(value instanceof Double) visitDoubleLiteral((Double) value); if(value instanceof Integer) @@ -1343,7 +1302,7 @@ public class BytecodeGenMethod implements StatementVisitor { break; } // Boxing - if (!type.equals("java/lang/String") && !type.equals("java/lang/Boolean")) { + if (!type.equals(CONSTANTS.REFTYPE_STRING) && !type.equals("java/lang/Boolean")) { if (!this.isBinaryExp && !isOperator) doBoxing(type); } @@ -1360,23 +1319,23 @@ public class BytecodeGenMethod implements StatementVisitor { case "java/lang/Boolean": mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false); break; - case "java/lang/Byte": - mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + case CONSTANTS.REFTYPE_BYTE: + mv.visitMethodInsn(Opcodes.INVOKESTATIC, CONSTANTS.REFTYPE_BYTE, "valueOf", "(B)Ljava/lang/Byte;", false); break; - case "java/lang/Short": - mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); + case CONSTANTS.REFTYPE_SHORT: + mv.visitMethodInsn(Opcodes.INVOKESTATIC, CONSTANTS.REFTYPE_SHORT, "valueOf", "(S)Ljava/lang/Short;", false); break; case "java/lang/Integer": mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); break; - case "java/lang/Long": - mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + case CONSTANTS.REFTYPE_LONG: + mv.visitMethodInsn(Opcodes.INVOKESTATIC, CONSTANTS.REFTYPE_LONG, "valueOf", "(J)Ljava/lang/Long;", false); break; - case "java/lang/Float": - mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + case CONSTANTS.REFTYPE_FLOAT: + mv.visitMethodInsn(Opcodes.INVOKESTATIC, CONSTANTS.REFTYPE_FLOAT, "valueOf", "(F)Ljava/lang/Float;", false); break; - case "java/lang/Double": - mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + case CONSTANTS.REFTYPE_DOUBLE: + mv.visitMethodInsn(Opcodes.INVOKESTATIC, CONSTANTS.REFTYPE_DOUBLE, "valueOf", "(D)Ljava/lang/Double;", false); break; case "java/lang/Character": mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", diff --git a/src/main/java/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java b/src/main/java/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java index 3fd10cf5..90064863 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java @@ -3,29 +3,27 @@ package de.dhbwstuttgart.bytecode.descriptor; import java.util.HashMap; import java.util.Iterator; +import de.dhbwstuttgart.bytecode.utilities.*; +import de.dhbwstuttgart.syntaxtree.statement.ArgumentList; import org.objectweb.asm.Type; -import de.dhbwstuttgart.bytecode.signature.TypeToSignature; -import de.dhbwstuttgart.bytecode.utilities.Lambda; -import de.dhbwstuttgart.bytecode.utilities.MethodFromMethodCall; -import de.dhbwstuttgart.bytecode.utilities.NormalConstructor; -import de.dhbwstuttgart.bytecode.utilities.NormalMethod; -import de.dhbwstuttgart.bytecode.utilities.SamMethod; import de.dhbwstuttgart.syntaxtree.FormalParameter; import de.dhbwstuttgart.syntaxtree.statement.Expression; -import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; import de.dhbwstuttgart.typeinference.result.ResultSet; -public class DescriptorToString implements DescriptorVisitor{ +public class DescriptorToString implements DescriptorVisitor, CONSTANTS { ResultSet resultSet; - + + public DescriptorToString() { + } + public DescriptorToString(ResultSet resultSet) { this.resultSet = resultSet; } private String addReturnType(String desc, RefTypeOrTPHOrWildcardOrGeneric returnType, ResultSet resultSet) { - if(resultSet.resolveType(returnType).resolvedType.toString().equals("void")){ + if(resultSet.resolveType(returnType).resolvedType.toString().equals(CONSTANTS.VOID)){ desc = desc + ")V"; }else { desc = desc + ")" + "L"+resultSet.resolveType(returnType).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; @@ -53,7 +51,7 @@ public class DescriptorToString implements DescriptorVisitor{ }else { // desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; String resType = resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()); - if(resType.contains("TPH ")/*resType.subSequence(0, 4).equals("TPH ")*/) { + if(resType.contains(CONSTANTS.TPH)/*resType.subSequence(0, 4).equals("TPH ")*/) { // Bound ist immer Object desc += "L"+Type.getInternalName(Object.class)+ ";"; } else { @@ -71,15 +69,15 @@ public class DescriptorToString implements DescriptorVisitor{ } } //TODO: generate a class java%% ... %% - else if(resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()).contains("<")){ - desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.toString().replace(".", "$$").replace("<", "$$$").replace(">", "$$$")+ ";"; + else if(resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()).contains(CONSTANTS.ANGLEBRACKET)){ + desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.toString().replace(".", "$$").replace(CONSTANTS.ANGLEBRACKET, "$$$").replace(">", "$$$")+ ";"; } else { desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; } } - if(resultSet.resolveType(method.getReturnType()).resolvedType.toString().equals("void")) { + if(resultSet.resolveType(method.getReturnType()).resolvedType.toString().equals(CONSTANTS.VOID)) { desc += ")V"; }else { if(method.hasGen()) { @@ -90,7 +88,7 @@ public class DescriptorToString implements DescriptorVisitor{ desc += ")L"+method.getGenericsAndBounds().get(ret)+ ";"; }else { String resType = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); - if(resType.contains("TPH ")/*resType.subSequence(0, 4).equals("TPH ")*/) { + if(resType.contains(CONSTANTS.TPH)/*resType.subSequence(0, 4).equals("TPH ")*/) { // desc += ")" + "L"+method.getGenericsAndBoundsMethod().get(resType.substring(4)+"$")+ ";"; desc += ")" + "L"+Type.getInternalName(Object.class)+ ";"; } else { @@ -139,7 +137,7 @@ public class DescriptorToString implements DescriptorVisitor{ }else { // desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; String resType = resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()); - if(resType.subSequence(0, 4).equals("TPH ")) { + if(resType.subSequence(0, 4).equals(CONSTANTS.TPH)) { // Bound ist immer Object desc += "L"+Type.getInternalName(Object.class)+ ";"; } else { @@ -162,7 +160,7 @@ public class DescriptorToString implements DescriptorVisitor{ while(itr.hasNext()) { FormalParameter fp = itr.next(); String d = resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()); - if(d.contains("TPH ") ||d.contains("<")) { + if(d.contains(CONSTANTS.TPH) ||d.contains(CONSTANTS.ANGLEBRACKET)) { desc += "L"+Type.getInternalName(Object.class)+ ";"; }else { desc = desc + "L"+ d + ";"; @@ -171,7 +169,7 @@ public class DescriptorToString implements DescriptorVisitor{ String retType = resultSet.resolveType(lambdaExpression.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); - if(retType.contains("TPH ")|| retType.contains("<")){ + if(retType.contains(CONSTANTS.TPH)|| retType.contains(CONSTANTS.ANGLEBRACKET)){ desc += ")L"+Type.getInternalName(Object.class)+ ";"; }else { desc = desc + ")"+"L"+retType+";"; @@ -187,7 +185,7 @@ public class DescriptorToString implements DescriptorVisitor{ RefTypeOrTPHOrWildcardOrGeneric rt = itr.next(); String d = resultSet.resolveType(rt).resolvedType.acceptTV(new TypeToDescriptor()); - if(d.contains("TPH ") ||d.contains("<")) { + if(d.contains(CONSTANTS.TPH) ||d.contains(CONSTANTS.ANGLEBRACKET)) { desc += "L"+Type.getInternalName(Object.class)+ ";"; }else { desc += "L"+ d + ";"; @@ -196,7 +194,7 @@ public class DescriptorToString implements DescriptorVisitor{ } String retType = resultSet.resolveType(samMethod.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); - if(retType.contains("TPH ")|| retType.contains("<")){ + if(retType.contains(CONSTANTS.TPH)|| retType.contains(CONSTANTS.ANGLEBRACKET)){ desc += ")L"+Type.getInternalName(Object.class)+ ";"; }else { desc = desc + ")"+"L"+retType+";"; @@ -210,7 +208,7 @@ public class DescriptorToString implements DescriptorVisitor{ for(Expression e : methodFromMethodCall.getArgList().getArguments()) { String d = resultSet.resolveType(e.getType()).resolvedType.acceptTV(new TypeToDescriptor()); - if(d.contains("TPH ") ||d.contains("<") || methodFromMethodCall.getReceiverName().contains("$$")) { + if(d.contains(CONSTANTS.TPH) ||d.contains(CONSTANTS.ANGLEBRACKET) || methodFromMethodCall.getReceiverName().contains("$$")) { desc += "L"+Type.getInternalName(Object.class)+ ";"; }else { if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(d)) { @@ -225,9 +223,9 @@ public class DescriptorToString implements DescriptorVisitor{ } String retType = resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); System.out.println("DescriptorToString retType = " + retType); - if(retType.equals("void")) { + if(retType.equals(CONSTANTS.VOID)) { desc += ")V"; - }else if(retType.contains("TPH ")|| retType.contains("<") || methodFromMethodCall.getReceiverName().contains("$$")){ + }else if(retType.contains(CONSTANTS.TPH)|| retType.contains(CONSTANTS.ANGLEBRACKET) || methodFromMethodCall.getReceiverName().contains("$$")){ desc += ")L"+Type.getInternalName(Object.class)+ ";"; }else { if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(retType)) { @@ -241,5 +239,21 @@ public class DescriptorToString implements DescriptorVisitor{ // desc = addReturnType(desc, methodFromMethodCall.getReturnType(), resultSet); return desc; } - + + @Override + public String createDescForFunN(ArgumentList argumentList, String returnType) { + Iterator itr1 = argumentList.getArguments().iterator(); + String methDesc = "("; + while(itr1.hasNext()) { + methDesc += "L" + Type.getInternalName(Object.class) + ";"; + itr1.next(); + } + if (returnType.equals(CONSTANTS.VOID)){ + methDesc += ")V"; + } else { + methDesc += ")L" + Type.getInternalName(Object.class) + ";"; + } + return methDesc; + } + } diff --git a/src/main/java/de/dhbwstuttgart/bytecode/descriptor/DescriptorVisitor.java b/src/main/java/de/dhbwstuttgart/bytecode/descriptor/DescriptorVisitor.java index 35f1423e..d1576c76 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/descriptor/DescriptorVisitor.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/descriptor/DescriptorVisitor.java @@ -5,11 +5,13 @@ import de.dhbwstuttgart.bytecode.utilities.MethodFromMethodCall; import de.dhbwstuttgart.bytecode.utilities.NormalConstructor; import de.dhbwstuttgart.bytecode.utilities.NormalMethod; import de.dhbwstuttgart.bytecode.utilities.SamMethod; +import de.dhbwstuttgart.syntaxtree.statement.ArgumentList; public interface DescriptorVisitor { - public String visit(NormalMethod method); - public String visit(NormalConstructor constructor); - public String visit(Lambda lambdaExpression); - public String visit(SamMethod samMethod); - public String visit(MethodFromMethodCall methodFromMethodCall); + String visit(NormalMethod method); + String visit(NormalConstructor constructor); + String visit(Lambda lambdaExpression); + String visit(SamMethod samMethod); + String visit(MethodFromMethodCall methodFromMethodCall); + String createDescForFunN(ArgumentList argumentList, String returnType); } diff --git a/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GenericsGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GenericsGenerator.java index 4b964d5c..a541025c 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GenericsGenerator.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/genericsGenerator/GenericsGenerator.java @@ -132,7 +132,7 @@ public class GenericsGenerator { return new GenericsGeneratorResult(constraint, equalSet); } - /* TODO Remove this method*/ + /* TODO Remove this methoda*/ private static GenericsGeneratorResult generateGGResultForClass(LinkedList tphsInRel, ConstraintsSimplierResult simplifiedConstraints, List tphsClass) { String subType = tphsInRel.getFirst(); diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java new file mode 100644 index 00000000..2de61726 --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java @@ -0,0 +1,94 @@ +package de.dhbwstuttgart.bytecode.utilities; + +import de.dhbwstuttgart.bytecode.signature.Signature; +import de.dhbwstuttgart.syntaxtree.FormalParameter; +import de.dhbwstuttgart.syntaxtree.statement.ArgumentList; +import de.dhbwstuttgart.syntaxtree.statement.Expression; +import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureVisitor; +import org.objectweb.asm.signature.SignatureWriter; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Iterator; + +public class ByteCodeForFunNGenerator { + + public static void generateBCForFunN(LambdaExpression lambdaExpression, String methDesc, String path) { + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + + SignatureWriter methSig = new SignatureWriter(); + + int numberOfParams = 0; + SignatureVisitor paramVisitor = methSig.visitParameterType(); + Iterator itr = lambdaExpression.params.iterator(); + while (itr.hasNext()) { + numberOfParams++; + // getBounds + paramVisitor.visitTypeVariable(CONSTANTS.T + numberOfParams); + itr.next(); + } + methSig.visitReturnType().visitTypeVariable(CONSTANTS.R); + // ")"+lam.getReturn.getBounds + Signature sig = new Signature(numberOfParams); + String name = CONSTANTS.FUN + numberOfParams + CONSTANTS.$$; + classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(), + Type.getInternalName(Object.class), null); + MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc, + methSig.toString(), null); + mvApply.visitEnd(); + writeClassFile(classWriter.toByteArray(), name, path); + } + + public static void generateBCForFunN(ArgumentList argumentList, String methDesc, String path) { + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + + SignatureWriter methSig = new SignatureWriter(); + + int numberOfParams = 0; + SignatureVisitor paramVisitor = methSig.visitParameterType(); + Iterator itr1 = argumentList.getArguments().iterator(); + + while(itr1.hasNext()) { + numberOfParams++; + // getBounds + paramVisitor.visitTypeVariable(CONSTANTS.T + numberOfParams); + itr1.next(); + } + + methSig.visitReturnType().visitTypeVariable(CONSTANTS.R); + // ")"+lam.getReturn.getBounds + Signature sig = new Signature(numberOfParams); + String name = CONSTANTS.FUN + numberOfParams + CONSTANTS.$$; + classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(), + Type.getInternalName(Object.class), null); + MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc, + methSig.toString(), null); + mvApply.visitEnd(); + writeClassFile(classWriter.toByteArray(), name, path); + } + + + public static void writeClassFile(byte[] bytecode, String name, String path) { + FileOutputStream output; + try { + System.out.println("generating " + name + ".class file..."); + output = new FileOutputStream( + new File(path + name + CONSTANTS.EXTENSIONCLASS)); + output.write(bytecode); + output.close(); + System.out.println(name + ".class file generated"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + } +} diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/CONSTANTS.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/CONSTANTS.java new file mode 100644 index 00000000..da05e82e --- /dev/null +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/CONSTANTS.java @@ -0,0 +1,22 @@ +package de.dhbwstuttgart.bytecode.utilities; + +public interface CONSTANTS { + + String VOID = "void"; + String TPH = "TPH "; + String ANGLEBRACKET = "<"; + String FUN = "Fun"; + String EXTENSIONCLASS = ".class"; + String $$ = "$$"; + String T = "T"; + String R = "R"; + String DESUGAREDMETHODNAME = "lambda$new$"; + String REFTYPE_BYTE = "java/lang/Byte"; + String REFTYPE_SHORT = "java/lang/Short"; + String REFTYPE_INTEGER = "java/lang/Integer"; + String REFTYPE_LONG = "java/lang/Long"; + String REFTYPE_DOUBLE = "java/lang/Double"; + String REFTYPE_FLOAT = "java/lang/Float"; + String REFTYPE_STRING = "java/lang/String"; + String TO_STRING = "toString"; +} diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/KindOfLambda.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/KindOfLambda.java index aeefda62..39339cbe 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/KindOfLambda.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/KindOfLambda.java @@ -1,6 +1,5 @@ package de.dhbwstuttgart.bytecode.utilities; -import de.dhbwstuttgart.exceptions.NotImplementedException; import de.dhbwstuttgart.syntaxtree.statement.*; import java.util.ArrayList; @@ -19,7 +18,8 @@ public class KindOfLambda implements StatementVisitor{ private boolean isInstanceCapturingLambda = false; private List argumentList = new ArrayList<>(); private ArrayList usedVars = new ArrayList<>(); - private boolean hasThis = false; + private ArrayList varsFromInnerLambdas = new ArrayList<>(); + private boolean thisUsed = false; private ArrayList definedLocals = new ArrayList<>(); public KindOfLambda(LambdaExpression lambdaExpression) { @@ -40,19 +40,20 @@ public class KindOfLambda implements StatementVisitor{ return argumentList; } - public boolean isHasThis() { - return hasThis; + public boolean isThisUsed() { + return thisUsed; } @Override public void visit(ArgumentList argumentList) { - // TODO Auto-generated method stub + argumentList.getArguments().forEach(a->a.accept(this)); } @Override public void visit(LambdaExpression lambdaExpression) { - + lambdaExpression.params.getFormalparalist().forEach(p->varsFromInnerLambdas.add(p.getName())); + lambdaExpression.methodBody.accept(this); } @Override @@ -111,9 +112,11 @@ public class KindOfLambda implements StatementVisitor{ @Override public void visit(LocalVar localVar) { - if(!contain(params, localVar.name) && !definedLocals.contains(localVar.name)) { + boolean addVar = !contain(params, localVar.name) && !definedLocals.contains(localVar.name) && + !varsFromInnerLambdas.contains(localVar.name) && !usedVars.contains(localVar.name); + if(addVar) { argumentList.add(localVar.getType()); - if(hasThis) { + if(thisUsed) { usedVars.add(1, localVar.name); } else { usedVars.add(0, localVar.name); @@ -141,12 +144,13 @@ public class KindOfLambda implements StatementVisitor{ @Override public void visit(MethodCall methodCall) { methodCall.receiver.accept(this); + methodCall.arglist.accept(this); } @Override public void visit(NewClass methodCall) { - // TODO Auto-generated method stub - + methodCall.receiver.accept(this); + methodCall.arglist.accept(this); } @Override @@ -190,8 +194,8 @@ public class KindOfLambda implements StatementVisitor{ @Override public void visit(This aThis) { - if(!hasThis) { - hasThis = true; + if(!thisUsed) { + thisUsed = true; this.argumentList.add(0,aThis.getType()); } if(!isInstanceCapturingLambda) { diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodCallHelper.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodCallHelper.java index ceb72fa0..00d6e308 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodCallHelper.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/MethodCallHelper.java @@ -3,45 +3,20 @@ */ package de.dhbwstuttgart.bytecode.utilities; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.signature.SignatureVisitor; -import org.objectweb.asm.signature.SignatureWriter; - import de.dhbwstuttgart.bytecode.Exception.NotInCurrentPackageException; import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString; import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor; -import de.dhbwstuttgart.bytecode.signature.Signature; import de.dhbwstuttgart.bytecode.signature.TypeToSignature; -import de.dhbwstuttgart.syntaxtree.ClassOrInterface; -import de.dhbwstuttgart.syntaxtree.FormalParameter; -import de.dhbwstuttgart.syntaxtree.GenericDeclarationList; -import de.dhbwstuttgart.syntaxtree.GenericTypeVar; -import de.dhbwstuttgart.syntaxtree.Method; -import de.dhbwstuttgart.syntaxtree.ParameterList; -import de.dhbwstuttgart.syntaxtree.SourceFile; +import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.statement.Expression; -import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression; import de.dhbwstuttgart.syntaxtree.statement.MethodCall; -import de.dhbwstuttgart.syntaxtree.type.GenericRefType; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; -import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.typeinference.result.ResultSet; import javassist.NotFoundException; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import java.util.*; /** * @author fayez @@ -244,83 +219,12 @@ public class MethodCallHelper { } } - public String generateBCForFunN() { - ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - - SignatureWriter methSig = new SignatureWriter(); - - int numberOfParams = 0; - SignatureVisitor paramVisitor = methSig.visitParameterType(); - Iterator itr1 = methCall.arglist.getArguments().iterator(); - String methDesc = "("; - while(itr1.hasNext()) { - numberOfParams++; - // getBounds - paramVisitor.visitTypeVariable("T" + numberOfParams); - methDesc += "L" + Type.getInternalName(Object.class) + ";"; - itr1.next(); - } - methDesc += ")L" + Type.getInternalName(Object.class) + ";"; - - methSig.visitReturnType().visitTypeVariable("R"); - // ")"+lam.getReturn.getBounds - Signature sig = new Signature(numberOfParams); - String name = "Fun" + numberOfParams + "$$"; - classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(), - Type.getInternalName(Object.class), null); - MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc, - methSig.toString(), null); - mvApply.visitEnd(); - writeClassFile(classWriter.toByteArray(), name); - return methDesc; - } - - public String generateBCForFunN(String returnType, String[] paramTypes) { - ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - - SignatureWriter methSig = new SignatureWriter(); - - int numberOfParams = 0; - SignatureVisitor paramVisitor = methSig.visitParameterType(); - Iterator itr1 = methCall.arglist.getArguments().iterator(); - String methDesc = "("; - while(itr1.hasNext()) { - numberOfParams++; - // getBounds - paramVisitor.visitTypeVariable("T" + numberOfParams); - methDesc += "L" + paramTypes[numberOfParams-1] + ";"; - itr1.next(); - } - methDesc += ")L" + returnType + ";"; - - methSig.visitReturnType().visitTypeVariable("R"); - // ")"+lam.getReturn.getBounds - Signature sig = new Signature(numberOfParams,returnType,paramTypes); - String name = "Fun" + numberOfParams + "$$"; - classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(), - Type.getInternalName(Object.class), null); - MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc, - methSig.toString(), null); - mvApply.visitEnd(); - writeClassFile(classWriter.toByteArray(), name); - return methDesc; + public void generateBCForFunN(String methodDescriptor) { + ByteCodeForFunNGenerator.generateBCForFunN(methCall.arglist,methodDescriptor,path); } - private void writeClassFile(byte[] bytecode, String name) { - FileOutputStream output; - try { - System.out.println("generating " + name + ".class file..."); - output = new FileOutputStream( - new File(path + name + ".class")); - output.write(bytecode); - output.close(); - System.out.println(name + ".class file generated"); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - + public String getDescriptorOfApplyMethod(String methodCallType) { + return new DescriptorToString().createDescForFunN(methCall.arglist, methodCallType); } /** diff --git a/src/test/java/bytecode/YTest.java b/src/test/java/bytecode/YTest.java index 524170eb..45373e2b 100644 --- a/src/test/java/bytecode/YTest.java +++ b/src/test/java/bytecode/YTest.java @@ -25,11 +25,11 @@ public class YTest { public void generateBC() throws Exception { path = System.getProperty("user.dir")+"/src/test/resources/bytecode/javFiles/Y.jav"; fileToTest = new File(path); -// compiler = new JavaTXCompiler(fileToTest); -// compiler.generateBytecode(System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/"); -// pathToClassFile = System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/"; -// loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); -// classToTest = loader.loadClass("Y"); + compiler = new JavaTXCompiler(fileToTest); + compiler.generateBytecode(System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/"); + pathToClassFile = System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/"; + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("Y"); /* instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); diff --git a/src/test/java/bytecode/mathStrucTest.java b/src/test/java/bytecode/mathStrucTest.java index 801de468..d0048f46 100644 --- a/src/test/java/bytecode/mathStrucTest.java +++ b/src/test/java/bytecode/mathStrucTest.java @@ -32,7 +32,7 @@ public class mathStrucTest { pathToClassFile = System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/"; loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); classToTest = loader.loadClass("mathStruc"); - instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + instanceOfClass = classToTest.getDeclaredConstructor(Object.class).newInstance("A"); } } diff --git a/src/test/resources/bytecode/javFiles/FieldTphConsMeth.jav b/src/test/resources/bytecode/javFiles/FieldTphConsMeth.jav index 5a550337..dd4d9bde 100644 --- a/src/test/resources/bytecode/javFiles/FieldTphConsMeth.jav +++ b/src/test/resources/bytecode/javFiles/FieldTphConsMeth.jav @@ -1,26 +1,26 @@ public class FieldTphConsMeth { a; - /*public FieldTphConsMeth(c) { + public FieldTphConsMeth(c) { a = id(c); - }*/ + } id(b) { return b; } - setA(x) { + /*setA(x) { a = x; return a; - } + }*/ m(x,y) { x = id(y); } - m2(x,y) { + /*m2(x,y) { x = setA(y); return x; - } + }*/ } \ No newline at end of file diff --git a/src/test/resources/bytecode/javFiles/mathStruc.jav b/src/test/resources/bytecode/javFiles/mathStruc.jav index 2a5f9816..5ee06793 100644 --- a/src/test/resources/bytecode/javFiles/mathStruc.jav +++ b/src/test/resources/bytecode/javFiles/mathStruc.jav @@ -1,10 +1,10 @@ -class mathStruc { +public class mathStruc { model; //Fun1*, Fun1*,MathStruc >> innerOp = (o) -> (ms) -> new mathStruc<>(o.apply(model,ms.model)); - mathStruc(m) { + public mathStruc(m) { model =m; //innerOp = (o) -> (ms) -> new mathStruc<>(o.apply(this.model,ms.model)); }