From ff2bca5ce56e0a3ffe6a35e9b39a6b6d79bfb120 Mon Sep 17 00:00:00 2001 From: Fayez Abu Alia Date: Tue, 12 Jun 2018 11:41:59 +0200 Subject: [PATCH] Alle TPHS einer Methode und pairs (TPH < SuperTPH) werden gesammelt, gemeinsamme TPHs werden bestimmt, die Klassenkopf als Type-Variables definiert werden sollen. Erzeugung von Signature angepasst. --- .../dhbwstuttgart/bytecode/BytecodeGen.java | 143 +++++++++++++--- .../bytecode/signature/Signature.java | 159 ++++++++++-------- .../bytecode/utilities/MethodAndTPH.java | 29 ++++ test/bytecode/javFiles/IfTest.jav | 3 + test/bytecode/javFiles/Tph2.jav | 10 ++ 5 files changed, 247 insertions(+), 97 deletions(-) create mode 100644 src/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java create mode 100644 test/bytecode/javFiles/Tph2.jav diff --git a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java index 7e337471..920cd095 100644 --- a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -17,6 +17,7 @@ import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString; import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor; import de.dhbwstuttgart.bytecode.signature.Signature; import de.dhbwstuttgart.bytecode.signature.TypeToString; +import de.dhbwstuttgart.bytecode.utilities.MethodAndTPH; import de.dhbwstuttgart.bytecode.utilities.NormalConstructor; import de.dhbwstuttgart.bytecode.utilities.NormalMethod; import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal; @@ -28,6 +29,7 @@ import de.dhbwstuttgart.syntaxtree.type.RefType; import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric; import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; +import de.dhbwstuttgart.typeinference.result.GenericInsertPair; import de.dhbwstuttgart.typeinference.result.ResultPair; import de.dhbwstuttgart.typeinference.result.ResultSet; @@ -50,6 +52,9 @@ public class BytecodeGen implements ASTVisitor { // stores generics and their bounds of method HashMap genericsAndBoundsMethod = new HashMap<>(); + private final ArrayList commonPairs = new ArrayList<>(); + private ArrayList ListOfMethodsAndTph = new ArrayList<>(); + HashMap methodParamsAndTypes = new HashMap<>(); byte[] bytecode; HashMap classFiles; @@ -90,6 +95,7 @@ public class BytecodeGen implements ASTVisitor { @Override public void visit(ClassOrInterface classOrInterface) { + className = classOrInterface.getClassName().toString(); cw.visitSource(className +".jav", null); @@ -97,27 +103,41 @@ public class BytecodeGen implements ASTVisitor { isInterface = (classOrInterface.getModifiers()&512)==512; int acc = isInterface?classOrInterface.getModifiers()+Opcodes.ACC_ABSTRACT:classOrInterface.getModifiers()+Opcodes.ACC_SUPER; - String sig = null; - /* if class has generics then creates signature - * Signature looks like: - * Superclass - */ - if(classOrInterface.getGenerics().iterator().hasNext()) { - Signature signature = new Signature(classOrInterface, genericsAndBounds); - sig = signature.toString(); - } - // needs implemented Interfaces? - cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString() - , sig, classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()), null); - for(Field f : classOrInterface.getFieldDecl()) { - f.accept(this); - } + // resultSet = listOfResultSets.get(0); boolean isConsWithNoParamsVisited = false; + boolean isVisited = false; for(ResultSet rs : listOfResultSets) { resultSet = rs; - + // Nur einmal ausführen!! + if(!isVisited) { + TPHExtractor tphExtractor = new TPHExtractor(); + classOrInterface.accept(tphExtractor); + + getCommonTPHS(tphExtractor); + ListOfMethodsAndTph = tphExtractor.ListOfMethodsAndTph; + String sig = null; + /* if class has generics then creates signature + * Signature looks like: + * Superclass + */ + if(classOrInterface.getGenerics().iterator().hasNext() || !commonPairs.isEmpty()) { + Signature signature = new Signature(classOrInterface, genericsAndBounds,commonPairs); + sig = signature.toString(); + System.out.println("Signature: => " + sig); + } + + cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString() + , sig, classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()), null); + + isVisited = true; + } + + for(Field f : classOrInterface.getFieldDecl()) { + f.accept(this); + } + for(Constructor c : classOrInterface.getConstructors()) { if(!isConsWithNoParamsVisited) c.accept(this); @@ -133,6 +153,36 @@ public class BytecodeGen implements ASTVisitor { } + private void getCommonTPHS(TPHExtractor tphExtractor) { + // Gemeinsame TPHs + ArrayList cTPHs = new ArrayList<>(); + // Alle TPHs der Felder speichern + for(TypePlaceholder tph : tphExtractor.allTPHS.keySet()) { + if(!tphExtractor.allTPHS.get(tph)) + cTPHs.add(tph); + } + + ArrayList tphsMethod = tphExtractor.ListOfMethodsAndTph; + // Für jede Methode speichere die gemeinsame TPHs: + // -> Für jedes Pair prüfe ob, auf der rechten Seite ein TPH steht, der + // in der Liste der TPHs der Methode enthalten ist. + // Wenn ja -> gemeinsamer TPH + for(MethodAndTPH m:tphsMethod){ + for(GenericInsertPair p : m.getPairs()){ + if(!m.getTphs().contains(p.TA2)) + cTPHs.add(p.TA2); + } + } + + for(TypePlaceholder tph : cTPHs) { + for(GenericInsertPair p : tphExtractor.allPairs) { + if(p.contains(tph)) + commonPairs.add(p); + } + } + + } + @Override public void visit(Constructor field) { field.getParameterList().accept(this); @@ -186,11 +236,6 @@ 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); @@ -220,11 +265,18 @@ public class BytecodeGen implements ASTVisitor { /* if method has generics or return type is TPH, create signature */ // 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, tphEx.allTPHS); + ArrayList pairs = new ArrayList<>(); + for(MethodAndTPH m : ListOfMethodsAndTph) { + if(m.getName().equals(method.name)) { + pairs = m.getPairs(); + break; + } + } + + Signature signature = new Signature(method, genericsAndBoundsMethod, genericsAndBounds,methodParamsAndTypes,resultSet, pairs); sig = signature.toString(); } - System.out.println(sig); + System.out.println(method.getName()+" ==> "+sig); NormalMethod meth = new NormalMethod(method,genericsAndBounds,genericsAndBoundsMethod,hasGen); methDesc = meth.accept(new DescriptorToString(resultSet)); @@ -481,12 +533,47 @@ public class BytecodeGen implements ASTVisitor { throw new NotImplementedException(); } - private class TPHEx extends AbstractASTWalker{ - // Liste enthält alle tph der Klasse - ArrayList allTPHS = new ArrayList<>(); + private class TPHExtractor extends AbstractASTWalker{ + // Alle TPHs der Felder werden iKopf der Klasse definiert + // alle TPHs der Klasse: (TPH, is in Method?) + final HashMap allTPHS = new HashMap<>(); + MethodAndTPH methodAndTph; + Boolean inMethod = false; + final ArrayList ListOfMethodsAndTph = new ArrayList<>(); + final ArrayList allPairs = new ArrayList<>(); + @Override public void visit(TypePlaceholder tph) { - allTPHS.add(tph); + if(resultSet.resolveType(tph).resolvedType instanceof TypePlaceholder) { + TypePlaceholder resolvedTPH = (TypePlaceholder) resultSet.resolveType(tph).resolvedType; + if(inMethod) + methodAndTph.getTphs().add(resolvedTPH); + + allTPHS.put(resolvedTPH,inMethod); + resultSet.resolveType(tph).additionalGenerics.forEach(ag ->{ + if(ag.contains(resolvedTPH)&&ag.TA1.equals(resolvedTPH)&&!contains(allPairs,ag)) { + if(inMethod) + methodAndTph.getPairs().add(ag); + allPairs.add(ag); + } + }); + } + } + private boolean contains(ArrayList pairs, GenericInsertPair genPair) { + for(int i=0; i methodParamsAndTypes; private ResultSet resultSet; - ArrayList allTPHS; + private ArrayList commonPairs; + private ArrayList methodPairs; - public Signature(ClassOrInterface classOrInterface, HashMap genericsAndBounds) { + public Signature(ClassOrInterface classOrInterface, HashMap genericsAndBounds,ArrayList commonPairs) { this.classOrInterface = classOrInterface; this.genericsAndBounds = genericsAndBounds; + this.commonPairs = commonPairs; sw = new SignatureWriter(); createSignatureForClassOrInterface(); } @@ -47,13 +49,14 @@ public class Signature { createSignatureForConsOrMethod(this.constructor,true); } - public Signature(Method method, HashMap genericsAndBoundsMethod, - HashMap methodParamsAndTypes, ResultSet resultSet, ArrayList allTPHS) { + public Signature(Method method, HashMap genericsAndBoundsMethod,HashMap genericsAndBounds, + HashMap methodParamsAndTypes, ResultSet resultSet, ArrayList methodPairs) { this.method = method; this.genericsAndBoundsMethod = genericsAndBoundsMethod; + this.genericsAndBounds = genericsAndBounds; this.methodParamsAndTypes = methodParamsAndTypes; this.resultSet = resultSet; - this.allTPHS = allTPHS; + this.methodPairs = methodPairs; sw = new SignatureWriter(); createSignatureForConsOrMethod(this.method,false); } @@ -98,75 +101,66 @@ public class Signature { GenericTypeVar g = itr.next(); getBoundsOfTypeVar(g,genericsAndBoundsMethod); } - // Wenn die RückgabeType eine TPH ist, wird als generic behandelt - // 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)); - genericsAndBoundsMethod.put(g, Type.getInternalName(Object.class)); - sw.visitClassBound().visitEnd(); - } - for(String paramName : methodParamsAndTypes.keySet()) { - RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName); - String pT = t.acceptTV(new TypeToSignature()); - // S.o - if(pT.substring(0,4).equals("TPH ") && !genericsAndBoundsMethod.containsKey(pT)) { - String gP = pT.substring(4)+"$"; - sw.visitFormalTypeParameter(gP); - - 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; + if(!methodPairs.isEmpty()) { + // Wenn die RückgabeType eine TPH ist, wird als generic behandelt + // 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 ")) { + String g = ret.substring(4)+"$"; + if(genericsAndBounds.containsKey(g)) { + genericsAndBoundsMethod.put(g, genericsAndBounds.get(g)); + }else { + sw.visitFormalTypeParameter(g); + sw.visitClassBound().visitClassType(Type.getInternalName(Object.class)); + genericsAndBoundsMethod.put(g, Type.getInternalName(Object.class)); + sw.visitClassBound().visitEnd(); + } + } + + // Parameters + for(String paramName : methodParamsAndTypes.keySet()) { + RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName); + String pT = t.acceptTV(new TypeToSignature()); + // S.o + if(pT.substring(0,4).equals("TPH ")) { + String gP = pT.substring(4)+"$"; + if(!genericsAndBounds.containsKey(gP) && !genericsAndBoundsMethod.containsKey(gP)) { + sw.visitFormalTypeParameter(gP); + String bound = Type.getInternalName(Object.class); + boolean isTypeVar = false; + for(GenericInsertPair pair : methodPairs) { + if(pT.substring(4).equals(pair.TA1.getName())) { + bound = pair.TA2.getName()+"$"; + isTypeVar = true; + break; + } + } + + if(isTypeVar) { + sw.visitClassBound().visitTypeVariable(bound); + }else { + sw.visitClassBound().visitClassType(bound); + sw.visitClassBound().visitEnd(); + } + + genericsAndBoundsMethod.put(gP, bound); } } - sw.visitClassBound().visitTypeVariable(bound); - } else { - bound = Type.getInternalName(Object.class); - sw.visitClassBound().visitClassType(bound); - } - genericsAndBoundsMethod.put(gP, bound); -// sw.visitClassBound().visitEnd(); } + +// methodPairs.forEach(p->{ +// String name = p.TA2.getName() + "$"; +// if(!genericsAndBoundsMethod.containsKey(name)) { +// sw.visitFormalTypeParameter(name); +// String bound = Type.getInternalName(Object.class); +// sw.visitClassBound().visitClassType(bound); +// sw.visitClassBound().visitEnd(); +// genericsAndBoundsMethod.put(name, bound); +// } +// }); } - 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); @@ -236,7 +230,34 @@ public class Signature { GenericTypeVar g = itr.next(); getBoundsOfTypeVar(g,genericsAndBounds); } - + if(!commonPairs.isEmpty()) { + ArrayList types = new ArrayList<>(); + ArrayList superTypes = new ArrayList<>(); + + for(GenericInsertPair p : commonPairs) { + types.add(p.TA1); + superTypes.add(p.TA2); + } + + for(GenericInsertPair p : commonPairs) { + String t = p.TA1.getName()+"$"; + String bound = p.TA2.getName()+"$"; + sw.visitFormalTypeParameter(t); + sw.visitClassBound().visitTypeVariable(bound); + genericsAndBounds.put(t, bound); + } + + for(GenericInsertPair p : commonPairs) { + if(!types.contains(p.TA2)) { + String t = p.TA2.getName()+"$"; + String bound = Type.getInternalName(Object.class); + sw.visitFormalTypeParameter(t); + sw.visitClassBound().visitClassType(bound); + genericsAndBounds.put(t, bound); + sw.visitClassBound().visitEnd(); + } + } + } sw.visitSuperclass().visitClassType(classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()));; sw.visitEnd(); } diff --git a/src/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java b/src/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java new file mode 100644 index 00000000..99ec3163 --- /dev/null +++ b/src/de/dhbwstuttgart/bytecode/utilities/MethodAndTPH.java @@ -0,0 +1,29 @@ +package de.dhbwstuttgart.bytecode.utilities; + +import java.util.ArrayList; + +import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; +import de.dhbwstuttgart.typeinference.result.GenericInsertPair; + +public class MethodAndTPH { + + private String name; + private final ArrayList tphs = new ArrayList<>(); + private final ArrayList pairs = new ArrayList<>(); + + public MethodAndTPH(String name) { + this.name = name; + } + + public ArrayList getTphs() { + return tphs; + } + + public ArrayList getPairs(){ + return pairs; + } + + public String getName() { + return name; + } +} diff --git a/test/bytecode/javFiles/IfTest.jav b/test/bytecode/javFiles/IfTest.jav index 806e2157..33f9ecba 100644 --- a/test/bytecode/javFiles/IfTest.jav +++ b/test/bytecode/javFiles/IfTest.jav @@ -1,3 +1,6 @@ +import java.lang.Integer; +import java.lang.Boolean; + public class IfTest{ Integer m1(Boolean b) { Integer i; diff --git a/test/bytecode/javFiles/Tph2.jav b/test/bytecode/javFiles/Tph2.jav new file mode 100644 index 00000000..c957eae6 --- /dev/null +++ b/test/bytecode/javFiles/Tph2.jav @@ -0,0 +1,10 @@ +public class Tph2 { + m(a,b){ + var c = m2(a,b); + return a; + } + + m2(a,b){ + return b; + } +} \ No newline at end of file