diff --git a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java index f9bf72ed..7e337471 100644 --- a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -186,6 +186,11 @@ public class BytecodeGen implements ASTVisitor { System.out.println("Method: "+method.name +" , paramsType: "+methParamTypes); String methDesc = null; + TPHEx tphEx = new TPHEx(); + method.accept(tphEx); + System.out.println("TPHs: \n"); + tphEx.allTPHS.forEach(e->System.out.println(e.getName())); + // Method getModifiers() ? int acc = isInterface?Opcodes.ACC_ABSTRACT:method.modifier; System.out.println(acc); @@ -216,10 +221,10 @@ public class BytecodeGen implements ASTVisitor { // zwite operand muss weggelassen werden if(hasGen||method.getReturnType().acceptTV(new TypeToString()).equals("TPH")) { // resultset hier zum testen - Signature signature = new Signature(method, genericsAndBoundsMethod, methodParamsAndTypes,resultSet); + Signature signature = new Signature(method, genericsAndBoundsMethod, methodParamsAndTypes,resultSet, tphEx.allTPHS); sig = signature.toString(); } -// System.out.println(sig); + System.out.println(sig); NormalMethod meth = new NormalMethod(method,genericsAndBounds,genericsAndBoundsMethod,hasGen); methDesc = meth.accept(new DescriptorToString(resultSet)); @@ -475,5 +480,14 @@ public class BytecodeGen implements ASTVisitor { public void visit(UnaryExpr unaryExpr) { throw new NotImplementedException(); } + + private class TPHEx extends AbstractASTWalker{ + // Liste enthält alle tph der Klasse + ArrayList allTPHS = new ArrayList<>(); + @Override + public void visit(TypePlaceholder tph) { + allTPHS.add(tph); + } + } } diff --git a/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java b/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java index 468b079b..00c8aa68 100644 --- a/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java +++ b/src/de/dhbwstuttgart/bytecode/BytecodeGenMethod.java @@ -34,10 +34,12 @@ import de.dhbwstuttgart.bytecode.utilities.Lambda; import de.dhbwstuttgart.bytecode.utilities.MethodFromMethodCall; import de.dhbwstuttgart.bytecode.utilities.SamMethod; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; +import de.dhbwstuttgart.syntaxtree.AbstractASTWalker; import de.dhbwstuttgart.syntaxtree.FormalParameter; import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.StatementVisitor; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.typeinference.result.ResultSet; public class BytecodeGenMethod implements StatementVisitor { @@ -1040,13 +1042,18 @@ public class BytecodeGenMethod implements StatementVisitor { String var = assignLeftSide.localVar.name; if (!paramsAndLocals.containsKey(var)) { paramsAndLocals.put(var, index + 1); - } else { - paramsAndLocals.put(var, index); + } + + mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.get(var)); + } + + private class TPHEx extends AbstractASTWalker{ + // Liste enthält alle tph der Methode + ArrayList allTPHS = new ArrayList<>(); + @Override + public void visit(TypePlaceholder tph) { + allTPHS.add(tph); } - - mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.size()); - // Debug::: - } } diff --git a/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java b/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java index 0e97ca4c..dfac0c00 100644 --- a/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java +++ b/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java @@ -2,6 +2,8 @@ package de.dhbwstuttgart.bytecode.descriptor; import java.util.Iterator; +import org.objectweb.asm.Type; + import de.dhbwstuttgart.bytecode.signature.TypeToSignature; import de.dhbwstuttgart.bytecode.utilities.Lambda; import de.dhbwstuttgart.bytecode.utilities.MethodFromMethodCall; @@ -49,7 +51,8 @@ public class DescriptorToString implements DescriptorVisitor{ // desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; String resType = resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()); if(resType.subSequence(0, 4).equals("TPH ")) { - desc += "L"+method.getGenericsAndBoundsMethod().get(resType.substring(4)+"$")+ ";"; + // Bound ist immer Object + desc += "L"+Type.getInternalName(Object.class)+ ";"; } else { desc += "L"+resType+ ";"; } @@ -76,7 +79,8 @@ public class DescriptorToString implements DescriptorVisitor{ }else { String resType = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); if(resType.subSequence(0, 4).equals("TPH ")) { - desc += ")" + "L"+method.getGenericsAndBoundsMethod().get(resType.substring(4)+"$")+ ";"; +// desc += ")" + "L"+method.getGenericsAndBoundsMethod().get(resType.substring(4)+"$")+ ";"; + desc += ")" + "L"+Type.getInternalName(Object.class)+ ";"; } else { desc += ")" + "L"+resType+ ";"; } @@ -142,17 +146,25 @@ public class DescriptorToString implements DescriptorVisitor{ String desc = "("; for(Expression e : methodFromMethodCall.getArgList().getArguments()) { String d = e.getType().acceptTV(new TypeToDescriptor()); - if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(d)) { - desc += "L"+methodFromMethodCall.getGenericsAndBoundsMethod().get(d)+ ";"; - }else if(methodFromMethodCall.getGenericsAndBounds().containsKey(d)) { - desc += "L"+methodFromMethodCall.getGenericsAndBounds().get(d)+ ";"; + + if(d.substring(0, 4).equals("TPH ")) { + desc += "L"+Type.getInternalName(Object.class)+ ";"; }else { - desc += "L"+resultSet.resolveType(e.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; + if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(d)) { + desc += "L"+methodFromMethodCall.getGenericsAndBoundsMethod().get(d)+ ";"; + }else if(methodFromMethodCall.getGenericsAndBounds().containsKey(d)) { + desc += "L"+methodFromMethodCall.getGenericsAndBounds().get(d)+ ";"; + }else { + desc += "L"+resultSet.resolveType(e.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; + } } + } if(resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.toString().equals("void")) { desc += ")V"; + }else if(resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()).substring(0, 4).equals("TPH ")){ + desc += ")L"+Type.getInternalName(Object.class)+ ";"; }else { String ret = resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(ret)) { diff --git a/src/de/dhbwstuttgart/bytecode/signature/Signature.java b/src/de/dhbwstuttgart/bytecode/signature/Signature.java index 48804661..5637ca18 100644 --- a/src/de/dhbwstuttgart/bytecode/signature/Signature.java +++ b/src/de/dhbwstuttgart/bytecode/signature/Signature.java @@ -1,5 +1,6 @@ package de.dhbwstuttgart.bytecode.signature; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -8,6 +9,7 @@ import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureWriter; import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor; +import de.dhbwstuttgart.syntaxtree.AbstractASTWalker; import de.dhbwstuttgart.syntaxtree.ClassOrInterface; import de.dhbwstuttgart.syntaxtree.Constructor; import de.dhbwstuttgart.syntaxtree.GenericTypeVar; @@ -15,6 +17,8 @@ import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression; import de.dhbwstuttgart.syntaxtree.type.GenericRefType; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; +import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; +import de.dhbwstuttgart.typeinference.result.GenericInsertPair; import de.dhbwstuttgart.typeinference.result.ResultSet; public class Signature { @@ -26,6 +30,7 @@ public class Signature { private Method method; private HashMap methodParamsAndTypes; private ResultSet resultSet; + ArrayList allTPHS; public Signature(ClassOrInterface classOrInterface, HashMap genericsAndBounds) { this.classOrInterface = classOrInterface; @@ -43,11 +48,12 @@ public class Signature { } public Signature(Method method, HashMap genericsAndBoundsMethod, - HashMap methodParamsAndTypes, ResultSet resultSet) { + HashMap methodParamsAndTypes, ResultSet resultSet, ArrayList allTPHS) { this.method = method; this.genericsAndBoundsMethod = genericsAndBoundsMethod; this.methodParamsAndTypes = methodParamsAndTypes; this.resultSet = resultSet; + this.allTPHS = allTPHS; sw = new SignatureWriter(); createSignatureForConsOrMethod(this.method,false); } @@ -96,6 +102,15 @@ public class Signature { // z.B: Type = TPH K => wird eine Formal Type Parameter K$ erzeugt und Bound = Object String ret = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature()); if(ret.substring(0,4).equals("TPH ")) { + /* (1) Wenn TPH X -> TPH Y, dann ersetze TPH X in allTPHs durch TPH Y, + * da X = Y (in RES) ist */ + if(method.getReturnType() instanceof TypePlaceholder) { + TypePlaceholder retTPH = (TypePlaceholder) method.getReturnType(); + TypePlaceholder resolvedTPH = (TypePlaceholder) resultSet.resolveType(method.getReturnType()).resolvedType; + + allTPHS.remove(retTPH); + allTPHS.add(resolvedTPH); + } String g = ret.substring(4)+"$"; sw.visitFormalTypeParameter(g); sw.visitClassBound().visitClassType(Type.getInternalName(Object.class)); @@ -110,12 +125,48 @@ public class Signature { if(pT.substring(0,4).equals("TPH ") && !genericsAndBoundsMethod.containsKey(pT)) { String gP = pT.substring(4)+"$"; sw.visitFormalTypeParameter(gP); - sw.visitClassBound().visitClassType(Type.getInternalName(Object.class)); - genericsAndBoundsMethod.put(gP, Type.getInternalName(Object.class)); - sw.visitClassBound().visitEnd(); + + String resolvedT = resultSet.resolveType(t).resolvedType.acceptTV(new TypeToSignature()); + String bound; + if(resolvedT.subSequence(0, 4).equals("TPH ")) { + /* TODO: Prüfe, ob man hier auch (1) braucht*/ + + int s = resultSet.resolveType(t).additionalGenerics.size(); + System.out.println(gP+"AdditionalG: "+s); + resultSet.resolveType(t).additionalGenerics.forEach(a->System.out.println(a.TA2.getName())); + Iterator itr2 = resultSet.resolveType(t).additionalGenerics.iterator(); + //TypePlaceholder temp = null; + bound = Type.getInternalName(Object.class); + while(itr2.hasNext()) { + TypePlaceholder tph = itr2.next().TA2; + String tphName = tph.getName()+"$"; + if(allTPHS.contains(tph) && !tphName.equals(gP)) { + bound = tphName; + break; + } + } + sw.visitClassBound().visitTypeVariable(bound); + } else { + bound = Type.getInternalName(Object.class); + sw.visitClassBound().visitClassType(bound); + } + genericsAndBoundsMethod.put(gP, bound); +// sw.visitClassBound().visitEnd(); } } + allTPHS.forEach(tph -> { + String tp = tph.getName()+"$"; + if(!genericsAndBoundsMethod.containsKey(tp)) { + sw.visitFormalTypeParameter(tp); + String bound = Type.getInternalName(Object.class); + sw.visitClassBound().visitClassType(bound); + sw.visitClassBound().visitEnd(); + genericsAndBoundsMethod.put(tp, bound); + } + }); + + // visit each method-parameter to create the signature for(String paramName : methodParamsAndTypes.keySet()) { RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName); @@ -125,15 +176,6 @@ public class Signature { if(isConstructor) { sw.visitReturnType().visitBaseType('V'); }else { -// String ret = resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToSignature()); -// if(ret.substring(0,4).equals("TPH ")) { -// String g = ret.substring(4); -// if(!genericsAndBoundsMethod.containsKey(g)) { -// genericsAndBoundsMethod.put(g, Type.getInternalName(Object.class)); -// } else { -// genericsAndBoundsMethod.put(g+"_", Type.getInternalName(Object.class)); -// } -// } RefTypeOrTPHOrWildcardOrGeneric returnType = method.getReturnType(); // return type deswegen ist false doVisitParamsOrReturn(returnType, false); diff --git a/test/bytecode/FacTest.java b/test/bytecode/FacTest.java index 0875db05..c4cab24e 100644 --- a/test/bytecode/FacTest.java +++ b/test/bytecode/FacTest.java @@ -37,8 +37,8 @@ public class FacTest { @Test public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Method getFac = classToTest.getDeclaredMethod("getFac", Integer.class); - Integer result = (Integer) getFac.invoke(instanceOfClass,3); - assertEquals(result, 6); + Double result = (Double) getFac.invoke(instanceOfClass,3); + assertEquals(result, 6.0); } } diff --git a/test/bytecode/TphTest.java b/test/bytecode/TphTest.java new file mode 100644 index 00000000..449db765 --- /dev/null +++ b/test/bytecode/TphTest.java @@ -0,0 +1,40 @@ +package bytecode; + +import static org.junit.Assert.*; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; + +import org.junit.BeforeClass; +import org.junit.Test; + +import de.dhbwstuttgart.core.JavaTXCompiler; + +public class TphTest { + private static String path; + private static File fileToTest; + private static JavaTXCompiler compiler; + private static ClassLoader loader; + private static Class classToTest; + private static String pathToClassFile; + private static Object instanceOfClass; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + path = System.getProperty("user.dir")+"/test/bytecode/javFiles/Tph.jav"; + fileToTest = new File(path); + compiler = new JavaTXCompiler(fileToTest); + compiler.generateBytecode(); + pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/"; + loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); + classToTest = loader.loadClass("Tph"); + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + } + + @Test + public void test() { + fail("Not yet implemented"); + } + +} diff --git a/test/bytecode/javFiles/Fac.jav b/test/bytecode/javFiles/Fac.jav index baee231b..eb2e6d61 100644 --- a/test/bytecode/javFiles/Fac.jav +++ b/test/bytecode/javFiles/Fac.jav @@ -4,7 +4,7 @@ import java.lang.Double; public class Fac { - java.lang.Long getFac(n){ + getFac(n){ var res = 1; var i = 1; while(i<=n) { diff --git a/test/bytecode/javFiles/Tph.jav b/test/bytecode/javFiles/Tph.jav new file mode 100644 index 00000000..3f9d0aab --- /dev/null +++ b/test/bytecode/javFiles/Tph.jav @@ -0,0 +1,11 @@ +public class Tph { + + m(a,b){ + var c = m2(b); + return a; + } + + m2(b){ + return b; + } +} \ No newline at end of file