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 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<Integer> 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<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;
SignatureVisitor paramVisitor = methSig.visitParameterType();
Iterator<Expression> 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;
}
}