forked from JavaTX/JavaCompilerCore
Compare commits
8 Commits
9ec4d59f24
...
typeErasur
Author | SHA1 | Date | |
---|---|---|---|
|
87064f8c7d | ||
|
c7c50f4669 | ||
|
65448c3bf3 | ||
|
ac6980b5e0 | ||
|
59d50bd2c6 | ||
|
c613ed7e12 | ||
|
2ba966a4e7 | ||
|
7eaddd67a3 |
@@ -584,6 +584,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: Für Type Erasure relevant?!
|
||||||
@Override
|
@Override
|
||||||
public void visit(LambdaExpression lambdaExpression) {
|
public void visit(LambdaExpression lambdaExpression) {
|
||||||
this.lamCounter++;
|
this.lamCounter++;
|
||||||
@@ -653,6 +654,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
// generateBCForFunN(lambdaExpression, typeErasure);
|
// generateBCForFunN(lambdaExpression, typeErasure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: Relevant?!
|
||||||
private String addUsedVarsToDesugaredMethodDescriptor(String lamDesc) {
|
private String addUsedVarsToDesugaredMethodDescriptor(String lamDesc) {
|
||||||
String newDesc = "(";
|
String newDesc = "(";
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
@@ -674,6 +676,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: Relevant?!
|
||||||
private String createDescriptorWithTypeErasure(LambdaExpression lambdaExpression) {
|
private String createDescriptorWithTypeErasure(LambdaExpression lambdaExpression) {
|
||||||
String typeErasure = "(";
|
String typeErasure = "(";
|
||||||
Iterator<FormalParameter> itr = lambdaExpression.params.iterator();
|
Iterator<FormalParameter> itr = lambdaExpression.params.iterator();
|
||||||
@@ -767,6 +770,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
// This will be used if the class is not standard class (not in API)
|
// This will be used if the class is not standard class (not in API)
|
||||||
ClassLoader cLoader2;
|
ClassLoader cLoader2;
|
||||||
|
|
||||||
|
//ToDo methodCallType wird nicht korrekt resolved, da kein Constraint vorhanden ist
|
||||||
String methCallType = resultSet.resolveType(methodCall.getType()).resolvedType.acceptTV(new TypeToDescriptor());
|
String methCallType = resultSet.resolveType(methodCall.getType()).resolvedType.acceptTV(new TypeToDescriptor());
|
||||||
String[] typesOfParams = getTypes(methodCall.arglist.getArguments());
|
String[] typesOfParams = getTypes(methodCall.arglist.getArguments());
|
||||||
try {
|
try {
|
||||||
@@ -811,11 +815,13 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
} catch (NotInCurrentPackageException | NotFoundException e) {
|
} catch (NotInCurrentPackageException | NotFoundException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
} else if(!helper.isInCurrPkg(clazz)){
|
} else if(!helper.isInCurrPkg(clazz)){
|
||||||
if(clazz.contains(CONSTANTS.$$)) {
|
if(clazz.contains(CONSTANTS.$$)) {
|
||||||
|
//ToDo Methoden Deskriptor neu setzen
|
||||||
|
//ToDo Receiver neu setzen?!
|
||||||
mDesc = helper.getDescriptorOfApplyMethod(methCallType);
|
mDesc = helper.getDescriptorOfApplyMethod(methCallType);
|
||||||
helper.generateBCForFunN(mDesc);
|
helper.generateBCForFunN(typesOfParams, methCallType);
|
||||||
// mDesc = helper.generateBCForFunN(methCallType,typesOfParams);
|
|
||||||
}else {
|
}else {
|
||||||
try {
|
try {
|
||||||
cLoader2 = new DirectoryClassLoader(path, classLoader);
|
cLoader2 = new DirectoryClassLoader(path, classLoader);
|
||||||
@@ -872,6 +878,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
if(parentBinary || isBinaryExp) {
|
if(parentBinary || isBinaryExp) {
|
||||||
doUnboxing(resolver.getResolvedType(methodCall.getType()));
|
doUnboxing(resolver.getResolvedType(methodCall.getType()));
|
||||||
}
|
}
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
} else if(receiverName.contains(CONSTANTS.$$) && !methCallType.equals(Type.getInternalName(Object.class))) {
|
} else if(receiverName.contains(CONSTANTS.$$) && !methCallType.equals(Type.getInternalName(Object.class))) {
|
||||||
helper.createCheckCast(methodCall,mv);
|
helper.createCheckCast(methodCall,mv);
|
||||||
}
|
}
|
||||||
@@ -899,6 +906,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
private void visitInvokeInsn(MethodCall methodCall, String receiverName, java.lang.reflect.Method methodRefl, String clazz, String mDesc, String receiverRefl) {
|
private void visitInvokeInsn(MethodCall methodCall, String receiverName, java.lang.reflect.Method methodRefl, String clazz, String mDesc, String receiverRefl) {
|
||||||
// is methodCall.receiver functional Interface)?
|
// is methodCall.receiver functional Interface)?
|
||||||
if (varsFunInterface.contains(methodCall.receiver.getType()) || (methodRefl!= null && receiverRefl.contains("interface")) ||
|
if (varsFunInterface.contains(methodCall.receiver.getType()) || (methodRefl!= null && receiverRefl.contains("interface")) ||
|
||||||
|
@@ -68,6 +68,7 @@ public class DescriptorToString implements DescriptorVisitor, CONSTANTS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
//TODO: generate a class java%% ... %%
|
//TODO: generate a class java%% ... %%
|
||||||
else if(resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()).contains(CONSTANTS.ANGLEBRACKET)){
|
else if(resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()).contains(CONSTANTS.ANGLEBRACKET)){
|
||||||
desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.toString().replace(".", "$$").replace(CONSTANTS.ANGLEBRACKET, "$$$").replace(">", "$$$")+ ";";
|
desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.toString().replace(".", "$$").replace(CONSTANTS.ANGLEBRACKET, "$$$").replace(">", "$$$")+ ";";
|
||||||
@@ -207,7 +208,7 @@ public class DescriptorToString implements DescriptorVisitor, CONSTANTS {
|
|||||||
String desc = "(";
|
String desc = "(";
|
||||||
for(Expression e : methodFromMethodCall.getArgList().getArguments()) {
|
for(Expression e : methodFromMethodCall.getArgList().getArguments()) {
|
||||||
String d = resultSet.resolveType(e.getType()).resolvedType.acceptTV(new TypeToDescriptor());
|
String d = resultSet.resolveType(e.getType()).resolvedType.acceptTV(new TypeToDescriptor());
|
||||||
|
//ToDo Etienne: Ändern von $$ nötig für TypeErasure?
|
||||||
if(d.contains(CONSTANTS.TPH) ||d.contains(CONSTANTS.ANGLEBRACKET) || methodFromMethodCall.getReceiverName().contains("$$")) {
|
if(d.contains(CONSTANTS.TPH) ||d.contains(CONSTANTS.ANGLEBRACKET) || methodFromMethodCall.getReceiverName().contains("$$")) {
|
||||||
desc += "L"+Type.getInternalName(Object.class)+ ";";
|
desc += "L"+Type.getInternalName(Object.class)+ ";";
|
||||||
}else {
|
}else {
|
||||||
@@ -225,6 +226,7 @@ public class DescriptorToString implements DescriptorVisitor, CONSTANTS {
|
|||||||
System.out.println("DescriptorToString retType = " + retType);
|
System.out.println("DescriptorToString retType = " + retType);
|
||||||
if(retType.equals(CONSTANTS.VOID)) {
|
if(retType.equals(CONSTANTS.VOID)) {
|
||||||
desc += ")V";
|
desc += ")V";
|
||||||
|
//ToDo Etienne: Ändern von $$ nötig für TypeErasure?
|
||||||
}else if(retType.contains(CONSTANTS.TPH)|| retType.contains(CONSTANTS.ANGLEBRACKET) || methodFromMethodCall.getReceiverName().contains("$$")){
|
}else if(retType.contains(CONSTANTS.TPH)|| retType.contains(CONSTANTS.ANGLEBRACKET) || methodFromMethodCall.getReceiverName().contains("$$")){
|
||||||
desc += ")L"+Type.getInternalName(Object.class)+ ";";
|
desc += ")L"+Type.getInternalName(Object.class)+ ";";
|
||||||
}else {
|
}else {
|
||||||
@@ -240,6 +242,7 @@ public class DescriptorToString implements DescriptorVisitor, CONSTANTS {
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: Ändern für TypeErasure
|
||||||
@Override
|
@Override
|
||||||
public String createDescForFunN(ArgumentList argumentList, String returnType) {
|
public String createDescForFunN(ArgumentList argumentList, String returnType) {
|
||||||
Iterator<Expression> itr1 = argumentList.getArguments().iterator();
|
Iterator<Expression> itr1 = argumentList.getArguments().iterator();
|
||||||
|
@@ -11,7 +11,9 @@ public interface DescriptorVisitor {
|
|||||||
String visit(NormalMethod method);
|
String visit(NormalMethod method);
|
||||||
String visit(NormalConstructor constructor);
|
String visit(NormalConstructor constructor);
|
||||||
String visit(Lambda lambdaExpression);
|
String visit(Lambda lambdaExpression);
|
||||||
|
//ToDo Etienne: Was ist SamMethod?
|
||||||
String visit(SamMethod samMethod);
|
String visit(SamMethod samMethod);
|
||||||
|
//ToDo Etienne: Was ist MethodFromMethodCall?
|
||||||
String visit(MethodFromMethodCall methodFromMethodCall);
|
String visit(MethodFromMethodCall methodFromMethodCall);
|
||||||
String createDescForFunN(ArgumentList argumentList, String returnType);
|
String createDescForFunN(ArgumentList argumentList, String returnType);
|
||||||
}
|
}
|
||||||
|
@@ -136,6 +136,7 @@ public class Signature {
|
|||||||
defineGenericsFromConstraints(constraints,genericsAndBoundsMethod);
|
defineGenericsFromConstraints(constraints,genericsAndBoundsMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: für TypeErasure anschauen
|
||||||
private void createSignatureForFunN(int numberOfParams, String to, String[] paramTypes) {
|
private void createSignatureForFunN(int numberOfParams, String to, String[] paramTypes) {
|
||||||
defineTypeVariablesForParametersOfFunN(numberOfParams);
|
defineTypeVariablesForParametersOfFunN(numberOfParams);
|
||||||
|
|
||||||
@@ -147,6 +148,7 @@ public class Signature {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: für TypeErasure anschauen
|
||||||
private void createSignatureForFunN(int numberOfParams) {
|
private void createSignatureForFunN(int numberOfParams) {
|
||||||
|
|
||||||
defineTypeVariablesForParametersOfFunN(numberOfParams);
|
defineTypeVariablesForParametersOfFunN(numberOfParams);
|
||||||
@@ -202,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 {
|
||||||
@@ -266,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 {
|
||||||
|
@@ -99,4 +99,34 @@ public class TypeToSignature implements TypeVisitor<String> {
|
|||||||
.filter(c -> c.getConstraint().getLeft().equals(tph) || c.getEqualsTPHs().contains(tph))
|
.filter(c -> c.getConstraint().getLeft().equals(tph) || c.getEqualsTPHs().contains(tph))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* //ToDo beschreiben
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* @since Studienarbeit Type Erasure
|
||||||
|
* @author Etienne Zink
|
||||||
|
*/
|
||||||
|
public String visit(RefTypeOrTPHOrWildcardOrGeneric type){
|
||||||
|
String returnString = "";
|
||||||
|
if (type instanceof GenericRefType){
|
||||||
|
GenericRefType genericRefType = (GenericRefType) type;
|
||||||
|
returnString += visit(genericRefType);
|
||||||
|
} else if (type instanceof RefType){
|
||||||
|
RefType refType = (RefType) type;
|
||||||
|
returnString += visit(refType);
|
||||||
|
} else if (type instanceof TypePlaceholder){
|
||||||
|
TypePlaceholder typePlaceholder = (TypePlaceholder) type;
|
||||||
|
returnString += visit(typePlaceholder);
|
||||||
|
} else if (type instanceof SuperWildcardType){
|
||||||
|
SuperWildcardType superWildcardType = (SuperWildcardType) type;
|
||||||
|
returnString += visit(superWildcardType);
|
||||||
|
} else if (type instanceof ExtendsWildcardType) {
|
||||||
|
ExtendsWildcardType extendsWildcardType = (ExtendsWildcardType) type;
|
||||||
|
returnString += visit(extendsWildcardType);
|
||||||
|
}
|
||||||
|
return returnString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,38 @@
|
|||||||
package de.dhbwstuttgart.bytecode.utilities;
|
package de.dhbwstuttgart.bytecode.utilities;
|
||||||
|
|
||||||
import de.dhbwstuttgart.bytecode.signature.Signature;
|
import de.dhbwstuttgart.bytecode.signature.Signature;
|
||||||
|
import de.dhbwstuttgart.bytecode.signature.TypeToSignature;
|
||||||
import de.dhbwstuttgart.syntaxtree.FormalParameter;
|
import de.dhbwstuttgart.syntaxtree.FormalParameter;
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.ArgumentList;
|
import de.dhbwstuttgart.syntaxtree.statement.ArgumentList;
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.Expression;
|
import de.dhbwstuttgart.syntaxtree.statement.Expression;
|
||||||
import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression;
|
import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression;
|
||||||
|
import de.dhbwstuttgart.syntaxtree.type.*;
|
||||||
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;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileNotFoundException;
|
import java.sql.Ref;
|
||||||
import java.io.FileOutputStream;
|
import java.util.HashSet;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.objectweb.asm.Opcodes.*;
|
||||||
|
|
||||||
public class ByteCodeForFunNGenerator {
|
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<>();
|
||||||
|
|
||||||
|
//ToDo Etienne: wird in Test OLFun nicht verwendet!
|
||||||
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);
|
||||||
|
|
||||||
@@ -38,57 +51,121 @@ 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(name, classWriter.toByteArray(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateBCForFunN(ArgumentList argumentList, String methDesc, File path) {
|
/**
|
||||||
|
* //ToDo beschreiben
|
||||||
|
*
|
||||||
|
* @param typesOfFormalParameters
|
||||||
|
* @param returnType
|
||||||
|
* @param path
|
||||||
|
*
|
||||||
|
* @since Studienarbeit Type Erasure
|
||||||
|
* @author Etienne Zink
|
||||||
|
*/
|
||||||
|
public static void generateBCForFunN(String[] typesOfFormalParameters, String returnType, File path) {
|
||||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
|
int numberOfParameters = typesOfFormalParameters.length;
|
||||||
|
generateSuperFunNInterface(numberOfParameters, path);
|
||||||
|
|
||||||
SignatureWriter methSig = new SignatureWriter();
|
String className = getBaseFunClassname(numberOfParameters);
|
||||||
|
String classSignature = String.format("L%s;L%s<", Type.getInternalName(Object.class), className);
|
||||||
|
|
||||||
int numberOfParams = 0;
|
//ToDo testen ob der Klassenname und -signatur so passt
|
||||||
SignatureVisitor paramVisitor = methSig.visitParameterType();
|
for (String typeOfFormalParameter: typesOfFormalParameters) {
|
||||||
Iterator<Expression> itr1 = argumentList.getArguments().iterator();
|
className += String.format("%s$_$", typeOfFormalParameter);
|
||||||
|
classSignature += String.format("L%s;", typeOfFormalParameter);
|
||||||
while(itr1.hasNext()) {
|
|
||||||
numberOfParams++;
|
|
||||||
// getBounds
|
|
||||||
paramVisitor.visitTypeVariable(CONSTANTS.T + numberOfParams);
|
|
||||||
itr1.next();
|
|
||||||
}
|
}
|
||||||
|
className += returnType;
|
||||||
|
className = className.replace('/', '$');
|
||||||
|
classSignature += String.format("L%s>;", returnType);
|
||||||
|
|
||||||
methSig.visitReturnType().visitTypeVariable(CONSTANTS.R);
|
System.out.println("Generated className: " + className);
|
||||||
// ")"+lam.getReturn.getBounds
|
System.out.println("Generated signature: " + classSignature);
|
||||||
Signature sig = new Signature(numberOfParams);
|
|
||||||
String name = CONSTANTS.FUN + numberOfParams + CONSTANTS.$$;
|
classWriter.visit(V1_8, ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT, className, classSignature,
|
||||||
classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC+Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT, name, sig.toString(),
|
Type.getInternalName(Object.class), new String[]{getBaseFunClassname(numberOfParameters)});
|
||||||
Type.getInternalName(Object.class), null);
|
writeClassFile(className, classWriter.toByteArray(), path);
|
||||||
MethodVisitor mvApply = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.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;
|
||||||
|
//ToDo Etienne: Generierung der Signaturen/Deskriptoren vielleicht auslagern? Bzw. schauen ob nicht schon vorhanden und anpassen!
|
||||||
|
String className = getBaseFunClassname(numberOfParameters);
|
||||||
|
String classSignature = "<";
|
||||||
|
String methodSignature = "(";
|
||||||
|
String methodDescriptor = "(";
|
||||||
|
for (int parameter = 1; parameter <= numberOfParameters; parameter++) {
|
||||||
|
classSignature += String.format("T%d:L%s;", parameter, Type.getInternalName(Object.class));
|
||||||
|
methodSignature += String.format("TT%d;", parameter);
|
||||||
|
methodDescriptor += String.format("L%s;", Type.getInternalName(Object.class));
|
||||||
|
}
|
||||||
|
classSignature += String.format("R:L%s;>L%s;",Type.getInternalName(Object.class),Type.getInternalName(Object.class));
|
||||||
|
methodSignature += ")TR;";
|
||||||
|
methodDescriptor += String.format(")L%s;",Type.getInternalName(Object.class));
|
||||||
|
|
||||||
public static void writeClassFile(byte[] bytecode, String name, File path) {
|
ClassWriter classWriter = new ClassWriter(0);
|
||||||
FileOutputStream output;
|
classWriter.visit(V1_8, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, className, classSignature, Type.getInternalName(Object.class), null);
|
||||||
try {
|
|
||||||
System.out.println("generating " + name + ".class file...");
|
MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, "apply", methodDescriptor, methodSignature, null);
|
||||||
output = new FileOutputStream(
|
methodVisitor.visitEnd();
|
||||||
new File(path , name + CONSTANTS.EXTENSIONCLASS));
|
classWriter.visitEnd();
|
||||||
|
|
||||||
|
byte[] bytecode = classWriter.toByteArray();
|
||||||
|
if(writeClassFile(className, bytecode, path)) {
|
||||||
|
alreadyGeneratedFunN.add(numberOfParameters);
|
||||||
|
}
|
||||||
|
return alreadyGeneratedFunN.contains(numberOfParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param countParameters
|
||||||
|
* @return the String of the super Fun$$ type
|
||||||
|
*
|
||||||
|
* @since Studienarbeit Type Erasure
|
||||||
|
* @author Etienne Zink
|
||||||
|
*/
|
||||||
|
private static String getBaseFunClassname(int countParameters){
|
||||||
|
return String.format("Fun%d$$", countParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -220,10 +220,13 @@ public class MethodCallHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateBCForFunN(String methodDescriptor) {
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
ByteCodeForFunNGenerator.generateBCForFunN(methCall.arglist,methodDescriptor,path);
|
public void generateBCForFunN(String[] typesOfFormalParams, String receiverType) {
|
||||||
|
//ToDo return Descriptor auf apply Methode?
|
||||||
|
ByteCodeForFunNGenerator.generateBCForFunN(typesOfFormalParams, receiverType,path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig
|
||||||
public String getDescriptorOfApplyMethod(String methodCallType) {
|
public String getDescriptorOfApplyMethod(String methodCallType) {
|
||||||
return new DescriptorToString().createDescForFunN(methCall.arglist, methodCallType);
|
return new DescriptorToString().createDescForFunN(methCall.arglist, methodCallType);
|
||||||
}
|
}
|
||||||
|
@@ -884,6 +884,7 @@ public class JavaTXCompiler {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?! (alle generatedBytecode-Methoden?)
|
||||||
public void generateBytecode() throws ClassNotFoundException, IOException, BytecodeGeneratorError {
|
public void generateBytecode() throws ClassNotFoundException, IOException, BytecodeGeneratorError {
|
||||||
generateBytecode((File) null);
|
generateBytecode((File) null);
|
||||||
}
|
}
|
||||||
|
@@ -185,6 +185,7 @@ public class TypeGenerator {
|
|||||||
}else{
|
}else{
|
||||||
Pattern p = Pattern.compile("Fun(\\d+)[$][$]");
|
Pattern p = Pattern.compile("Fun(\\d+)[$][$]");
|
||||||
Matcher m = p.matcher(name);
|
Matcher m = p.matcher(name);
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
if (m.matches()) {//es ist FunN$$-Type
|
if (m.matches()) {//es ist FunN$$-Type
|
||||||
return new RefType(new JavaClassName(name), convert(typeArguments, reg, generics), offset);
|
return new RefType(new JavaClassName(name), convert(typeArguments, reg, generics), offset);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -9,6 +9,7 @@ import org.antlr.v4.runtime.Token;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//ToDo Etienne: Wieso abstrakte Klasse? -> Dadurch keine Inferenz mit ? möglich!
|
||||||
public abstract class WildcardType extends RefTypeOrTPHOrWildcardOrGeneric {
|
public abstract class WildcardType extends RefTypeOrTPHOrWildcardOrGeneric {
|
||||||
|
|
||||||
protected RefTypeOrTPHOrWildcardOrGeneric innerType = null;
|
protected RefTypeOrTPHOrWildcardOrGeneric innerType = null;
|
||||||
|
@@ -63,6 +63,7 @@ public class MethodAssumption extends Assumption{
|
|||||||
//Die Generics werden alle zu TPHs umgewandelt.
|
//Die Generics werden alle zu TPHs umgewandelt.
|
||||||
params.add(resolver.resolve(new GenericRefType(gtv.getName(), new NullToken())));
|
params.add(resolver.resolve(new GenericRefType(gtv.getName(), new NullToken())));
|
||||||
}
|
}
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
RefTypeOrTPHOrWildcardOrGeneric receiverType;
|
RefTypeOrTPHOrWildcardOrGeneric receiverType;
|
||||||
if(receiver instanceof FunNClass){
|
if(receiver instanceof FunNClass){
|
||||||
receiverType = new RefType(new JavaClassName(receiver.getClassName().toString()+"$$"), params, new NullToken()); // new FunN(params);
|
receiverType = new RefType(new JavaClassName(receiver.getClassName().toString()+"$$"), params, new NullToken()); // new FunN(params);
|
||||||
|
@@ -68,6 +68,7 @@ public class TYPEStmt implements StatementVisitor{
|
|||||||
lambdaParams.add(tphRetType);
|
lambdaParams.add(tphRetType);
|
||||||
//lambdaParams.add(0,tphRetType);
|
//lambdaParams.add(0,tphRetType);
|
||||||
constraintsSet.addUndConstraint(
|
constraintsSet.addUndConstraint(
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
new Pair(lambdaExpression.getType(),
|
new Pair(lambdaExpression.getType(),
|
||||||
new RefType(new JavaClassName("Fun"+(lambdaParams.size()-1)+"$$"), lambdaParams, new NullToken()),
|
new RefType(new JavaClassName("Fun"+(lambdaParams.size()-1)+"$$"), lambdaParams, new NullToken()),
|
||||||
//new FunN(lambdaParams),
|
//new FunN(lambdaParams),
|
||||||
|
@@ -21,6 +21,7 @@ public class FunNType extends UnifyType {
|
|||||||
/**
|
/**
|
||||||
* Creates a FunN-Type with the specified TypeParameters.
|
* Creates a FunN-Type with the specified TypeParameters.
|
||||||
*/
|
*/
|
||||||
|
//ToDo Etienne: Für Type Erasure wichtig?!
|
||||||
protected FunNType(TypeParams p) {
|
protected FunNType(TypeParams p) {
|
||||||
super("Fun"+(p.size()-1)+"$$", p);
|
super("Fun"+(p.size()-1)+"$$", p);
|
||||||
}
|
}
|
||||||
|
@@ -1,52 +1,65 @@
|
|||||||
package bytecode;
|
package bytecode;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
import org.junit.Test;
|
import general.TestCleanUp;
|
||||||
|
import org.junit.*;
|
||||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test which only checks if the class {@code OLFun} was correctly compiled.
|
||||||
|
* This is achived by verifying the existence of the three implementations of {@code m}.
|
||||||
|
*
|
||||||
|
* @since Studienarbeit Type Erasure
|
||||||
|
* @author Etienne Zink
|
||||||
|
*/
|
||||||
public class OLFunTest {
|
public class OLFunTest {
|
||||||
private static String path;
|
private static String path;
|
||||||
private static File fileToTest;
|
private static File fileToTest;
|
||||||
private static JavaTXCompiler compiler;
|
private static JavaTXCompiler compiler;
|
||||||
private static ClassLoader loader;
|
private static ClassLoader loader;
|
||||||
private static Class<?> classToTest;
|
private static Class<?> classToTest;
|
||||||
private static String pathToClassFile;
|
private static Class<?> classFun1;
|
||||||
private static Object instanceOfClass;
|
private static Object instanceOfClass;
|
||||||
|
|
||||||
|
private static String generatedByteCodeDirectory = System.getProperty("user.dir") + "/src/test/resources/testBytecode/generatedBC/";
|
||||||
|
|
||||||
@Test
|
@BeforeClass
|
||||||
public void generateBC() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
path = System.getProperty("user.dir")+"/src/test/resources/bytecode/javFiles/OLFun.jav";
|
path = System.getProperty("user.dir")+"/src/test/resources/bytecode/javFiles/OLFun.jav";
|
||||||
fileToTest = new File(path);
|
fileToTest = new File(path);
|
||||||
compiler = new JavaTXCompiler(fileToTest);
|
compiler = new JavaTXCompiler(fileToTest);
|
||||||
compiler.generateBytecode(System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/");
|
compiler.generateBytecode(generatedByteCodeDirectory);
|
||||||
pathToClassFile = System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/";
|
loader = new URLClassLoader(new URL[] {new URL("file://"+generatedByteCodeDirectory)});
|
||||||
loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
|
|
||||||
classToTest = loader.loadClass("OLFun");
|
classToTest = loader.loadClass("OLFun");
|
||||||
/*
|
classFun1 = loader.loadClass("Fun1$$");
|
||||||
instanceOfClass = classToTest.getDeclaredConstructor().newInstance();
|
instanceOfClass = classToTest.getDeclaredConstructor().newInstance();
|
||||||
|
|
||||||
Method m = classToTest.getDeclaredMethod("m");
|
|
||||||
Class<?> lambda = m.invoke(instanceOfClass).getClass();
|
|
||||||
Method apply = lambda.getMethod("apply", Object.class);
|
|
||||||
|
|
||||||
// Damit man auf die Methode zugreifen kann
|
|
||||||
apply.setAccessible(true);
|
|
||||||
|
|
||||||
Integer i = 77;
|
|
||||||
|
|
||||||
Integer result = (Integer) apply.invoke(m.invoke(instanceOfClass), i);
|
|
||||||
|
|
||||||
assertEquals(77, result);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mExistsWithInteger() throws Exception{
|
||||||
|
Method m = classToTest.getDeclaredMethod("m", classFun1 ,Integer.class);
|
||||||
|
assertNotNull(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mExistsWithString() throws Exception{
|
||||||
|
Method m = classToTest.getDeclaredMethod("m", classFun1 ,String.class);
|
||||||
|
assertNotNull(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mExistsWithDouble() throws Exception{
|
||||||
|
Method m = classToTest.getDeclaredMethod("m", classFun1 ,Double.class);
|
||||||
|
assertNotNull(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void cleanUp(){
|
||||||
|
TestCleanUp.cleanUpDirectory(new File(generatedByteCodeDirectory), f -> f.getName().contains(".class"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
14
src/test/java/general/TestCleanUp.java
Normal file
14
src/test/java/general/TestCleanUp.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package general;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
|
||||||
|
public class TestCleanUp {
|
||||||
|
|
||||||
|
public static void cleanUpDirectory(File directory, FileFilter fileFilter){
|
||||||
|
if(!directory.isDirectory()) throw new RuntimeException("Directory for bytecode generation is wrong!");
|
||||||
|
for (File file: directory.listFiles(fileFilter)) {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -10,7 +10,6 @@ import java.lang.Boolean;
|
|||||||
public class OLFun {
|
public class OLFun {
|
||||||
|
|
||||||
//f = x -> {return x + x;};
|
//f = x -> {return x + x;};
|
||||||
|
|
||||||
m(f, x) {
|
m(f, x) {
|
||||||
x = f.apply(x+x);
|
x = f.apply(x+x);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user