From 59d50bd2c6e77ed52febc3faea8b8a00f5a2142e Mon Sep 17 00:00:00 2001 From: Etienne Zink Date: Wed, 16 Mar 2022 15:39:21 +0100 Subject: [PATCH] Refactoring der writeClassFile-Methode in ByteCodeForFunNGenerator. --- .../utilities/ByteCodeForFunNGenerator.java | 94 ++++++++++--------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java index 28323643..db0e0876 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/ByteCodeForFunNGenerator.java @@ -7,7 +7,6 @@ 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; @@ -15,6 +14,7 @@ import org.objectweb.asm.signature.SignatureWriter; import java.io.*; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import static org.objectweb.asm.Opcodes.*; @@ -22,6 +22,9 @@ public class ByteCodeForFunNGenerator { /** * HashSet which contains the parameter number for which already a FunN$$ interface was generated. + * + * @since Studienarbeit Type Erasure + * @author Etienne Zink */ private static HashSet alreadyGeneratedFunN = new HashSet<>(); @@ -48,53 +51,56 @@ public class ByteCodeForFunNGenerator { MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc, methSig.toString(), null); mvApply.visitEnd(); - writeClassFile(classWriter.toByteArray(), name, path); + writeClassFile(name, classWriter.toByteArray(), path); } public static void generateBCForFunN(ArgumentList argumentList, String methDesc, File path) { ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + List arguments = argumentList.getArguments(); + /* //ToDo neu machen + int numberOfParams = arguments.size(); + //ToDo Classname anpassen + String className = CONSTANTS.FUN + numberOfParams + CONSTANTS.$$; - SignatureWriter methSig = new SignatureWriter(); + Signature sig = new Signature(numberOfParams); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT, className, sig.toString(), + Type.getInternalName(Object.class), new String[]{String.format("Fun%d$$", numberOfParams)}); + writeClassFile(className, classWriter.toByteArray(), path); + */ + + SignatureWriter signatureWriter = new SignatureWriter(); int numberOfParams = 0; - SignatureVisitor paramVisitor = methSig.visitParameterType(); - Iterator itr1 = argumentList.getArguments().iterator(); + SignatureVisitor paramVisitor = signatureWriter.visitParameterType(); - while(itr1.hasNext()) { - numberOfParams++; - // getBounds - paramVisitor.visitTypeVariable(CONSTANTS.T + numberOfParams); - itr1.next(); + for (Expression argument:arguments) { + paramVisitor.visitTypeVariable(CONSTANTS.T + ++numberOfParams); } - methSig.visitReturnType().visitTypeVariable(CONSTANTS.R); - // ")"+lam.getReturn.getBounds + signatureWriter.visitReturnType().visitTypeVariable(CONSTANTS.R); 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(V1_8, ACC_PUBLIC + ACC_INTERFACE + ACC_ABSTRACT, name, sig.toString(), - Type.getInternalName(Object.class), null); - MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc, - methSig.toString(), null); + classWriter.visit(V1_8, ACC_PUBLIC + ACC_INTERFACE + ACC_ABSTRACT, name, sig.toString(), Type.getInternalName(Object.class), null); + MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc, signatureWriter.toString(), null); mvApply.visitEnd(); - writeClassFile(classWriter.toByteArray(), name, path); + writeClassFile(name, classWriter.toByteArray(), path); } /** - * Function which generates a {@code .class-File} for the super interface + * 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 + * @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); + //ToDo Etienne: Generierung der Signaturen/Deskriptoren vielleicht auslagern? + String className = String.format("Fun%d$$", numberOfParameters); String classSignature = "<"; String methodSignature = "("; String methodDescriptor = "("; @@ -108,38 +114,38 @@ public class ByteCodeForFunNGenerator { 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); + classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, className, 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(); + if(writeClassFile(className, bytecode, path)) { alreadyGeneratedFunN.add(numberOfParameters); - } catch (Exception e) { - e.printStackTrace(); } return alreadyGeneratedFunN.contains(numberOfParameters); } - - public static void writeClassFile(byte[] bytecode, String name, File path) { - FileOutputStream output; - try { - System.out.println("generating " + name + ".class file..."); - output = new FileOutputStream( - new File(path , name + CONSTANTS.EXTENSIONCLASS)); + /** + * Generates a {@code class-File} for the class {@code className} with the {@code bytecode}. + * + * @param className of the class to generate + * @param bytecode of the class + * @param directory where the class should be saved to + * @return {@code true}, iff the {@code class-File} could be generated. + * + * @since Studienarbeit Type Erasure + * @author Etienne Zink + */ + private static boolean writeClassFile(String className, byte[] bytecode, File directory) { + try (FileOutputStream output = new FileOutputStream(new File(directory , className + CONSTANTS.EXTENSIONCLASS))){ output.write(bytecode); - output.close(); - System.out.println(name + ".class file generated"); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { + output.flush(); + return true; + } catch (Exception e) { e.printStackTrace(); } - + return false; } -} +} \ No newline at end of file