Added Method to ByteCodeForFunNGenerator which generates the basic interface FunN$$.

This commit is contained in:
Etienne Zink 2022-03-16 14:29:09 +01:00
parent 2ba966a4e7
commit c613ed7e12
2 changed files with 61 additions and 15 deletions

View File

@ -204,6 +204,7 @@ public class Signature {
if (r instanceof GenericRefType) { if (r instanceof GenericRefType) {
sv.visitTypeVariable(sig2); sv.visitTypeVariable(sig2);
} else if (!(r instanceof TypePlaceholder)) { } else if (!(r instanceof TypePlaceholder)) {
//ToDo Etienne: Wichtig für Type Erasure?!
if (sig2.contains(SPECIAL_CHAR_FOR_FUN)) { if (sig2.contains(SPECIAL_CHAR_FOR_FUN)) {
sv.visitInterface().visitClassType(sig2.substring(1)); sv.visitInterface().visitClassType(sig2.substring(1));
} else { } else {
@ -268,6 +269,7 @@ public class Signature {
} }
private void checkInnerSignatureOfWildCard(SignatureVisitor sv, String sigInner, int length, char superOrExtendsChar) { 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)) { if (sigInner.contains(SPECIAL_CHAR_FOR_FUN)) {
sv.visitTypeArgument(superOrExtendsChar).visitInterface().visitClassType(sigInner.substring(1, length)); sv.visitTypeArgument(superOrExtendsChar).visitInterface().visitClassType(sigInner.substring(1, length));
} else { } else {

View File

@ -12,21 +12,19 @@ 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;
import java.io.File; import java.io.*;
import java.io.FileNotFoundException; import java.util.HashSet;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
//ToDo Etienne: Anpassung für TypeErasure import static org.objectweb.asm.Opcodes.*;
//static Attribut (HashSet<int>) 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?
public class ByteCodeForFunNGenerator { public class ByteCodeForFunNGenerator {
/**
* HashSet which contains the parameter number for which already a FunN$$ interface was generated.
*/
private static HashSet<Integer> alreadyGeneratedFunN = new HashSet<>();
public static void generateBCForFunN(LambdaExpression lambdaExpression, String methDesc, File path) { public static void generateBCForFunN(LambdaExpression lambdaExpression, String methDesc, File path) {
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
@ -45,9 +43,9 @@ public class ByteCodeForFunNGenerator {
// ")"+lam.getReturn.getBounds // ")"+lam.getReturn.getBounds
Signature sig = new Signature(numberOfParams); Signature sig = new Signature(numberOfParams);
String name = CONSTANTS.FUN + numberOfParams + CONSTANTS.$$; 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); 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); methSig.toString(), null);
mvApply.visitEnd(); mvApply.visitEnd();
writeClassFile(classWriter.toByteArray(), name, path); writeClassFile(classWriter.toByteArray(), name, path);
@ -72,15 +70,61 @@ public class ByteCodeForFunNGenerator {
methSig.visitReturnType().visitTypeVariable(CONSTANTS.R); methSig.visitReturnType().visitTypeVariable(CONSTANTS.R);
// ")"+lam.getReturn.getBounds // ")"+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(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); 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); methSig.toString(), null);
mvApply.visitEnd(); mvApply.visitEnd();
writeClassFile(classWriter.toByteArray(), name, path); 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) { public static void writeClassFile(byte[] bytecode, String name, File path) {
FileOutputStream output; FileOutputStream output;