Refactoring der writeClassFile-Methode in ByteCodeForFunNGenerator.

This commit is contained in:
Etienne Zink 2022-03-16 15:39:21 +01:00
parent c613ed7e12
commit 59d50bd2c6

View File

@ -7,7 +7,6 @@ import de.dhbwstuttgart.syntaxtree.statement.Expression;
import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression; import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.signature.SignatureWriter; import org.objectweb.asm.signature.SignatureWriter;
@ -15,6 +14,7 @@ import org.objectweb.asm.signature.SignatureWriter;
import java.io.*; import java.io.*;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import static org.objectweb.asm.Opcodes.*; 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. * HashSet which contains the parameter number for which already a FunN$$ interface was generated.
*
* @since Studienarbeit Type Erasure
* @author Etienne Zink
*/ */
private static HashSet<Integer> alreadyGeneratedFunN = new HashSet<>(); private static HashSet<Integer> alreadyGeneratedFunN = new HashSet<>();
@ -48,53 +51,56 @@ public class ByteCodeForFunNGenerator {
MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc, MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc,
methSig.toString(), null); methSig.toString(), null);
mvApply.visitEnd(); mvApply.visitEnd();
writeClassFile(classWriter.toByteArray(), name, path); writeClassFile(name, classWriter.toByteArray(), path);
} }
public static void generateBCForFunN(ArgumentList argumentList, String methDesc, File path) { public static void generateBCForFunN(ArgumentList argumentList, String methDesc, File path) {
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
List<Expression> 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; int numberOfParams = 0;
SignatureVisitor paramVisitor = methSig.visitParameterType(); SignatureVisitor paramVisitor = signatureWriter.visitParameterType();
Iterator<Expression> itr1 = argumentList.getArguments().iterator();
while(itr1.hasNext()) { for (Expression argument:arguments) {
numberOfParams++; paramVisitor.visitTypeVariable(CONSTANTS.T + ++numberOfParams);
// getBounds
paramVisitor.visitTypeVariable(CONSTANTS.T + numberOfParams);
itr1.next();
} }
methSig.visitReturnType().visitTypeVariable(CONSTANTS.R); signatureWriter.visitReturnType().visitTypeVariable(CONSTANTS.R);
// ")"+lam.getReturn.getBounds
Signature sig = new Signature(numberOfParams); 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.$$; String name = CONSTANTS.FUN + numberOfParams + CONSTANTS.$$;
classWriter.visit(V1_8, ACC_PUBLIC + ACC_INTERFACE + ACC_ABSTRACT, name, sig.toString(), classWriter.visit(V1_8, ACC_PUBLIC + ACC_INTERFACE + ACC_ABSTRACT, name, sig.toString(), Type.getInternalName(Object.class), null);
Type.getInternalName(Object.class), null); MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc, signatureWriter.toString(), null);
MethodVisitor mvApply = classWriter.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "apply", methDesc,
methSig.toString(), null);
mvApply.visitEnd(); 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. * Fun<{@code numberOfParameters}>$$ if it doesn't exist already.
*
* @param numberOfParameters * @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}. * based on {@link #alreadyGeneratedFunN alreadyGeneratedFunN}.
*
* @since Studienarbeit Type Erase * @since Studienarbeit Type Erase
* @author Etienne Zink * @author Etienne Zink
*/ */
public static boolean generateSuperFunNInterface(int numberOfParameters, File path){ public static boolean generateSuperFunNInterface(int numberOfParameters, File path){
if(alreadyGeneratedFunN.contains(numberOfParameters)) return true; if(alreadyGeneratedFunN.contains(numberOfParameters)) return true;
//ToDo Etienne: Generierung der Signaturen/Deskriptoren vielleicht auslagern?
String funNName = String.format("Fun%d$$", numberOfParameters); String className = String.format("Fun%d$$", numberOfParameters);
String classSignature = "<"; String classSignature = "<";
String methodSignature = "("; String methodSignature = "(";
String methodDescriptor = "("; String methodDescriptor = "(";
@ -108,38 +114,38 @@ public class ByteCodeForFunNGenerator {
methodDescriptor += ")Ljava/lang/Object;"; methodDescriptor += ")Ljava/lang/Object;";
ClassWriter classWriter = new ClassWriter(0); 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 methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", methodDescriptor, methodSignature, null);
methodVisitor.visitEnd(); methodVisitor.visitEnd();
classWriter.visitEnd(); classWriter.visitEnd();
byte[] bytecode = classWriter.toByteArray(); byte[] bytecode = classWriter.toByteArray();
try (BufferedOutputStream writer = new BufferedOutputStream(new FileOutputStream(new File(path, funNName + ".class")))) { if(writeClassFile(className, bytecode, path)) {
writer.write(bytecode);
writer.flush();
alreadyGeneratedFunN.add(numberOfParameters); alreadyGeneratedFunN.add(numberOfParameters);
} catch (Exception e) {
e.printStackTrace();
} }
return alreadyGeneratedFunN.contains(numberOfParameters); return alreadyGeneratedFunN.contains(numberOfParameters);
} }
/**
public static void writeClassFile(byte[] bytecode, String name, File path) { * Generates a {@code class-File} for the class {@code className} with the {@code bytecode}.
FileOutputStream output; *
try { * @param className of the class to generate
System.out.println("generating " + name + ".class file..."); * @param bytecode of the class
output = new FileOutputStream( * @param directory where the class should be saved to
new File(path , name + CONSTANTS.EXTENSIONCLASS)); * @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.write(bytecode);
output.close(); output.flush();
System.out.println(name + ".class file generated"); return true;
} catch (FileNotFoundException e) { } catch (Exception e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
return false;
} }
} }