diff --git a/src/main/java/de/dhbwstuttgart/bytecode/signature/Signature.java b/src/main/java/de/dhbwstuttgart/bytecode/signature/Signature.java index 3855b7d4..ee0258ad 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/signature/Signature.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/signature/Signature.java @@ -204,6 +204,7 @@ public class Signature { if (r instanceof GenericRefType) { sv.visitTypeVariable(sig2); } else if (!(r instanceof TypePlaceholder)) { + //ToDo Etienne: Wichtig für Type Erasure?! if (sig2.contains(SPECIAL_CHAR_FOR_FUN)) { sv.visitInterface().visitClassType(sig2.substring(1)); } else { @@ -268,6 +269,7 @@ public class Signature { } private void checkInnerSignatureOfWildCard(SignatureVisitor sv, String sigInner, int length, char superOrExtendsChar) { + //ToDo Etienne: Wichtig für Type Erasure?! if (sigInner.contains(SPECIAL_CHAR_FOR_FUN)) { sv.visitTypeArgument(superOrExtendsChar).visitInterface().visitClassType(sigInner.substring(1, length)); } else { diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java index d7035ec5..28323643 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java @@ -12,21 +12,19 @@ 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.io.*; +import java.util.HashSet; import java.util.Iterator; -//ToDo Etienne: Anpassung für TypeErasure -//static Attribut (HashSet) welches Anzahl Attribute hält -> Wenn Anzahl Attribute vorhanden, dann existiert Interface bereits -//schneller als bytecode auf Vorhandensein zu prüfen?! -//Wenn FunN$$ nicht vorhanden, dann erstellen -//Name ändern nach Konvention (FunN$$$_$...$_$) -//Muss FunN$$$_$...$_$ nun Interface sein oder? -//Frage: Worin wird Implementierung "gespeichert"?! --> Was/Wo ist der Bytecode hierfür? +import static org.objectweb.asm.Opcodes.*; + public class ByteCodeForFunNGenerator { + /** + * HashSet which contains the parameter number for which already a FunN$$ interface was generated. + */ + private static HashSet alreadyGeneratedFunN = new HashSet<>(); + public static void generateBCForFunN(LambdaExpression lambdaExpression, String methDesc, File path) { ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); @@ -45,9 +43,9 @@ public class ByteCodeForFunNGenerator { // ")"+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(), + classWriter.visit(V1_8, ACC_PUBLIC + ACC_INTERFACE + ACC_ABSTRACT, name, sig.toString(), Type.getInternalName(Object.class), null); - MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc, + MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc, methSig.toString(), null); mvApply.visitEnd(); writeClassFile(classWriter.toByteArray(), name, path); @@ -72,15 +70,61 @@ public class ByteCodeForFunNGenerator { methSig.visitReturnType().visitTypeVariable(CONSTANTS.R); // ")"+lam.getReturn.getBounds Signature sig = new Signature(numberOfParams); + //ToDo Name anpassen und Signatur? + //ToDo super anpassen + //ToDo extends FunN$$ einfügen und Parameter dazu String name = CONSTANTS.FUN + numberOfParams + CONSTANTS.$$; - classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(), + classWriter.visit(V1_8, ACC_PUBLIC + ACC_INTERFACE + ACC_ABSTRACT, name, sig.toString(), Type.getInternalName(Object.class), null); - MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "apply", methDesc, + MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc, methSig.toString(), null); mvApply.visitEnd(); writeClassFile(classWriter.toByteArray(), name, path); } + /** + * Function which generates a {@code .class-File} for the super interface + * Fun<{@code numberOfParameters}>$$ if it doesn't exist already. + * @param numberOfParameters + * @return {@code true}, iff the {@code .class-File} exists after this method invocation + * based on {@link #alreadyGeneratedFunN alreadyGeneratedFunN}. + * @since Studienarbeit Type Erase + * @author Etienne Zink + */ + public static boolean generateSuperFunNInterface(int numberOfParameters, File path){ + if(alreadyGeneratedFunN.contains(numberOfParameters)) return true; + + String funNName = String.format("Fun%d$$", numberOfParameters); + String classSignature = "<"; + String methodSignature = "("; + String methodDescriptor = "("; + for (int parameter = 1; parameter <= numberOfParameters; parameter++) { + classSignature += String.format("T%d:Ljava/lang/Object;", parameter); + methodSignature += String.format("TT%d;", parameter); + methodDescriptor += "Ljava/lang/Object;"; + } + classSignature += "R:Ljava/lang/Object;>Ljava/lang/Object;"; + methodSignature += ")TR;"; + methodDescriptor += ")Ljava/lang/Object;"; + + ClassWriter classWriter = new ClassWriter(0); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, funNName, classSignature, "java/lang/Object", null); + + MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", methodDescriptor, methodSignature, null); + methodVisitor.visitEnd(); + classWriter.visitEnd(); + + byte[] bytecode = classWriter.toByteArray(); + try (BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream(new File(path, funNName + ".class")))) { + writer.write(bytecode); + writer.flush(); + alreadyGeneratedFunN.add(numberOfParameters); + } catch (Exception e) { + e.printStackTrace(); + } + return alreadyGeneratedFunN.contains(numberOfParameters); + } + public static void writeClassFile(byte[] bytecode, String name, File path) { FileOutputStream output;