From d4d668b662804c83150b6ea6a1acb7574872141b Mon Sep 17 00:00:00 2001 From: Fayez Abu Alia Date: Wed, 16 Jan 2019 14:41:33 +0100 Subject: [PATCH] Simplify fuer Klassen Type Variablen --- .../dhbwstuttgart/bytecode/BytecodeGen.java | 35 +-- .../dhbwstuttgart/bytecode/TPHExtractor.java | 8 + .../bytecode/utilities/Simplify.java | 239 ++++++++++++++++++ .../syntaxtree/AbstractASTWalker.java | 3 + src/test/java/bytecode/FieldTph.java | 43 ---- .../java/bytecode/FieldTphConsMethTest.java | 3 +- src/test/java/bytecode/MatrixOpTest.java | 22 +- .../resources/bytecode/javFiles/MatrixOP.jav | 2 +- 8 files changed, 288 insertions(+), 67 deletions(-) delete mode 100644 src/test/java/bytecode/FieldTph.java diff --git a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java index 0dea801d8..fec01c104 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/BytecodeGen.java @@ -147,23 +147,7 @@ public class BytecodeGen implements ASTVisitor { if(!tphExtractor.allTPHS.get(t)) tphsClass.add(t); } - - ArrayList consClass = new ArrayList<>(); - for(TPHConstraint cons : tphExtractor.allCons) { - TypePlaceholder right = null; - for(TypePlaceholder tph : tphsClass) { - if(cons.getLeft().equals(tph.getName())) { - - consClass.add(cons); - right = getTPH(cons.getRight()); - } - } - if(right != null) { - tphsClass.add(right); - removeFromMethod(right.getName()); - right = null; - } - } + String sig = null; /* if class has generics then creates signature * Signature looks like: @@ -172,6 +156,23 @@ public class BytecodeGen implements ASTVisitor { if(classOrInterface.getGenerics().iterator().hasNext() || !commonPairs.isEmpty() || classOrInterface.getSuperClass().acceptTV(new TypeToSignature()).contains("<") || !tphsClass.isEmpty()) { + HashMap> constraints = Simplify.simplifyConstraintsClass(tphExtractor,tphsClass); + ArrayList consClass = new ArrayList<>(); + for(TPHConstraint cons : constraints.keySet()) { + TypePlaceholder right = null; + for(TypePlaceholder tph : tphsClass) { + if(cons.getLeft().equals(tph.getName())) { + + consClass.add(cons); + right = getTPH(cons.getRight()); + } + } + if(right != null) { + tphsClass.add(right); + removeFromMethod(right.getName()); + right = null; + } + } Signature signature = new Signature(classOrInterface, genericsAndBounds,commonPairs,tphsClass, consClass); sig = signature.toString(); System.out.println("Signature: => " + sig); diff --git a/src/main/java/de/dhbwstuttgart/bytecode/TPHExtractor.java b/src/main/java/de/dhbwstuttgart/bytecode/TPHExtractor.java index d9a953113..0135631ed 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/TPHExtractor.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/TPHExtractor.java @@ -11,6 +11,7 @@ import de.dhbwstuttgart.bytecode.constraint.TPHConstraint; import de.dhbwstuttgart.bytecode.constraint.TPHConstraint.Relation; import de.dhbwstuttgart.bytecode.utilities.MethodAndTPH; import de.dhbwstuttgart.syntaxtree.AbstractASTWalker; +import de.dhbwstuttgart.syntaxtree.Constructor; import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.typeinference.result.GenericInsertPair; @@ -75,4 +76,11 @@ public class TPHExtractor extends AbstractASTWalker{ ListOfMethodsAndTph.add(methodAndTph); } + @Override + public void visit(Constructor cons) { + inMethod = false; + super.visit(cons); + inMethod = true; + } + } \ No newline at end of file diff --git a/src/main/java/de/dhbwstuttgart/bytecode/utilities/Simplify.java b/src/main/java/de/dhbwstuttgart/bytecode/utilities/Simplify.java index d19d38dc8..2e3ce775d 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/utilities/Simplify.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/utilities/Simplify.java @@ -347,6 +347,245 @@ public class Simplify { return result; } + + public static HashMap> simplifyConstraintsClass(TPHExtractor tphExtractor, ArrayList tphsClass) { + // all constraints that will be simplified + ArrayList allCons = tphExtractor.allCons; + ArrayList consToRemove = new ArrayList<>(); + + // step 1: + for(TPHConstraint c : allCons) { + + String left = c.getLeft(); + String right = c.getRight(); + if(c.getRel() == Relation.EXTENDS) { + TPHConstraint revCon = getReverseConstraint(allCons,left,right); + if(revCon != null) { + revCon.setRel(Relation.EQUAL); + // the reverse constraint is removed because + // otherwise there is the same constraint twice + // (e.g. A A=B and B=A) + consToRemove.add(revCon); + c.setRel(Relation.EQUAL); + substituteTPH(allCons,left, right); + } + } + } + + + allCons.removeAll(consToRemove); + consToRemove = new ArrayList<>(); + + int size = allCons.size(); + + HashMap> result = new HashMap<>(); + + // check if there is any long cycle (e.g. A allTypes = new LinkedList<>(); + // we will put all constraints which are in the cycle, in this ArrayList. + // Later these contraints will be converted to equal-constraints + ArrayList constraints = new ArrayList<>(size); + int visited = 0; + + // contains all constraints + HashMap ss1 = new HashMap<>(); + + for(TPHConstraint constr : allCons) { + ss1.put(constr.getLeft(), constr.getRight()); + } + + for(TPHConstraint c : allCons) { + + if(visited >= size) + break; + // Only extends-constraints will be checked + if(c.getRel() == Relation.EXTENDS) { + ++visited; + + String left = c.getLeft(); + String right = c.getRight(); + // put the types in linked list + allTypes.add(left); + allTypes.add(right); + + constraints.add(c); + + boolean isCycle = false; + + // iterate through the map to check if there is a cycle + while(ss1.containsKey(right)) { + ++visited; + String oldRight = right; + right = ss1.get(right); + + TPHConstraint toAdd = getConstraint(oldRight, right, allCons); + + if(toAdd != null) + constraints.add(toAdd); + + if(left.equals(right)) { + isCycle = true; + break; + } + + allTypes.add(right); + } + + if(isCycle) { + // convert all constraints to equal constraints + setAllEqual(constraints); + // these constraints will be removed from allCons + consToRemove.addAll(constraints); + // all equal types will be substitute with one type + substituteAllTPH(allCons,constraints,left); + + HashSet eq = new HashSet<>(); + // put all equal types in a set + for(String t:allTypes) { + eq.add(t); + } + // generate a new constraint (left < Object) + TPHConstraint constraint = new ExtendsConstraint(left, Type.getInternalName(Object.class), Relation.EXTENDS); + // put the generated constraint and its equal set into result set + result.put(constraint, eq); + constraints.clear(); + } + allTypes.clear(); + } + } + // build an equal set that contains all types + // which are equal and for each equal constraint put left side and right side + // in this set Then generate a constraint type < Object and put it + // with the equal set into the result. + for(TPHConstraint c : allCons) { + if(c.getRel()==Relation.EQUAL) { + if(!isTPHInResEqual(result, c.getLeft())) { + HashSet equalTPHs = getEqualsTPHs(result, c); + TPHConstraint constraint = getKeyConstraint(result,c); + equalTPHs.add(c.getLeft()); + equalTPHs.add(c.getRight()); + result.put(constraint, equalTPHs); + } + consToRemove.add(c); + size--; + } + } + + // remove all equal-constraints + allCons.removeAll(consToRemove); + // add all generated constraints to allCons + allCons.addAll(result.keySet()); + + if(!allCons.isEmpty() && allCons.size()<2) { + TPHConstraint cons = allCons.get(0); + if(!result.containsKey(cons)) { + result.put(cons, null); + result.put(new ExtendsConstraint(cons.getRight(), Type.getInternalName(Object.class), Relation.EXTENDS), null); + } + + return result; + } + + size += result.keySet().size(); + // all constraints which have Object on the right side will + // be ignored, because they are simplified and can not be changed. + for(TPHConstraint c : allCons) { + if(c.getRight().equals(Type.getInternalName(Object.class))) + size--; + } + + // check if there are multiple constraint with the same left side. + // if yes => check if the super type in the method, if not + // then ignore it. + HashMap subAndSuper = new HashMap<>(); + ArrayList eqCons = new ArrayList<>(); + for(TPHConstraint c : allCons) { + + subAndSuper.put(c.getLeft(), c.getRight()); + } + + int numOfVisitedPairs = 0; + for(String sub : subAndSuper.keySet()) { + if(isTPHInConstraint(result,sub)) + continue; + + if(!classTPHSContainsTPH(tphsClass,sub)) + continue; + + if(numOfVisitedPairs>=size) + break; + LinkedList tphInRel = new LinkedList<>(); + tphInRel.add(sub); + String superT = subAndSuper.get(sub); + tphInRel.add(superT); + + numOfVisitedPairs++; + while(subAndSuper.containsKey(superT)) { + superT = subAndSuper.get(superT); + if(tphInRel.contains(superT)) { + break; + } + tphInRel.add(superT); + numOfVisitedPairs++; + } + + // Subtype + String subTphRes = tphInRel.getFirst(); + // Die größte Supertype + String superTphRes = tphInRel.getLast(); + + // if there is any constraint X < subTph, then + // add X at the beginning of the list. + while(subAndSuper.containsValue(subTphRes)) { + for(String tph : subAndSuper.keySet()) { + if(classTPHSContainsTPH(tphsClass,tph) && subAndSuper.get(tph).equals(subTphRes)) { + subTphRes = tph; + break; + } + } + if(subTphRes.equals(tphInRel.getFirst())) { + break; + } + + if(isTPHInConstraint(result, subTphRes)) + break; + + tphInRel.addFirst(subTphRes); + numOfVisitedPairs++; + } + + subTphRes = tphInRel.getFirst(); + + + + HashSet equals = getEqualsTphsFromEqualCons(eqCons,superTphRes); + result.put(new ExtendsConstraint(subTphRes, superTphRes, Relation.EXTENDS), equals); + + } + + System.out.println("EndResult: "); + result.forEach((c,hs)->{ + if(c!=null) { + System.out.print(c.toString() + " -> "); + if(hs == null) { + System.out.print(" [] "); + }else { + hs.forEach(s->{ + System.out.print(s + ", "); + }); + } + } + + + System.out.println(); + }); + System.out.println("----------------"); + return result; + } + + private static boolean classTPHSContainsTPH(ArrayList tphsClass, String superTphRes) { for(TypePlaceholder tph : tphsClass) { if(tph.getName().equals(superTphRes)) diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java b/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java index bf9fe2637..6fd83f3b4 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/AbstractASTWalker.java @@ -80,6 +80,9 @@ public abstract class AbstractASTWalker implements ASTVisitor{ for(Field f : classOrInterface.getFieldDecl()){ f.accept(this); } + for(Constructor c : classOrInterface.getConstructors()){ + c.accept(this); + } for(Method m : classOrInterface.getMethods()){ m.accept(this); } diff --git a/src/test/java/bytecode/FieldTph.java b/src/test/java/bytecode/FieldTph.java deleted file mode 100644 index 65c7f2917..000000000 --- a/src/test/java/bytecode/FieldTph.java +++ /dev/null @@ -1,43 +0,0 @@ -package bytecode; - -import static org.junit.Assert.*; - -import java.io.File; -import java.lang.reflect.Field; -import java.net.URL; -import java.net.URLClassLoader; - -import org.junit.BeforeClass; -import org.junit.Test; - -import de.dhbwstuttgart.core.JavaTXCompiler; - -public class FieldTph { - - 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")+"/src/test/resources/bytecode/javFiles/FieldTph.jav"; - fileToTest = new File(path); - compiler = new JavaTXCompiler(fileToTest); - compiler.generateBytecode(System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/"); - pathToClassFile = System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/"; - loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); - classToTest = loader.loadClass("FieldTph"); - instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); - } - - @Test - public void test() { - Field[] fields = classToTest.getFields(); - assertEquals(1, fields.length); - } - -} diff --git a/src/test/java/bytecode/FieldTphConsMethTest.java b/src/test/java/bytecode/FieldTphConsMethTest.java index ecf992d01..382c31e49 100644 --- a/src/test/java/bytecode/FieldTphConsMethTest.java +++ b/src/test/java/bytecode/FieldTphConsMethTest.java @@ -32,11 +32,11 @@ public class FieldTphConsMethTest { pathToClassFile = System.getProperty("user.dir")+"/src/test/resources/testBytecode/generatedBC/"; loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); classToTest = loader.loadClass("FieldTphConsMeth"); - instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); } @Test public void test() throws Exception { + instanceOfClass = classToTest.getConstructor(Object.class).newInstance("C"); Field a = classToTest.getDeclaredField("a"); a.setAccessible(true); @@ -44,6 +44,7 @@ public class FieldTphConsMethTest { Object result = m.invoke(instanceOfClass, 42); assertEquals(42,result); + assertEquals("C", a.get(instanceOfClass)); } } diff --git a/src/test/java/bytecode/MatrixOpTest.java b/src/test/java/bytecode/MatrixOpTest.java index 110187018..ea9068531 100644 --- a/src/test/java/bytecode/MatrixOpTest.java +++ b/src/test/java/bytecode/MatrixOpTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.*; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; @@ -27,7 +28,7 @@ public class MatrixOpTest { private static Object instanceOfClass_m3; @Test - public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IOException, InstantiationException { + public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IOException, InstantiationException, NoSuchFieldException { path = System.getProperty("user.dir")+"/src/test/resources/bytecode/javFiles/MatrixOP.jav"; fileToTest = new File(path); compiler = new JavaTXCompiler(fileToTest); @@ -35,7 +36,7 @@ public class MatrixOpTest { compiler.generateBytecode(pathToClassFile); loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)}); classToTest = loader.loadClass("MatrixOP"); -/* + Vector> vv = new Vector>(); Vector v1 = new Vector (); v1.addElement(2); @@ -48,6 +49,7 @@ public class MatrixOpTest { //m1.addElement(v2); vv.addElement(v1); vv.addElement(v2); + instanceOfClass_m1 = classToTest.getDeclaredConstructor(Vector.class).newInstance(vv); //Matrix m1 = new Matrix(vv); Vector> vv1 = new Vector>(); @@ -62,13 +64,23 @@ public class MatrixOpTest { //m2.addElement(v4); vv1.addElement(v3); vv1.addElement(v4); + instanceOfClass_m2 = classToTest.getDeclaredConstructor(Vector.class).newInstance(vv1);//Matrix m2 = new Matrix(vv1); //Matrix m3 = m1.mul(vv1); - Method mul = classToTest.getDeclaredMethod("mul", Vector.class); - Object result = mul.invoke(instanceOfClass_m1, instanceOfClass_m2); +// Method mul = classToTest.getDeclaredMethod("mul", Vector.class); +// Object result = mul.invoke(instanceOfClass_m1, instanceOfClass_m2); + Field mul = classToTest.getField("mul"); + mul.setAccessible(true); + + Class lambda = mul.get(instanceOfClass_m1).getClass(); + Method apply = lambda.getMethod("apply", Object.class,Object.class); + // Damit man auf die Methode zugreifen kann + apply.setAccessible(true); + + Object result = apply.invoke(mul.get(instanceOfClass_m1),instanceOfClass_m1, instanceOfClass_m2); System.out.println(instanceOfClass_m1.toString() + " * " + instanceOfClass_m2.toString() + " = " + result.toString()); Vector> res = new Vector>(); @@ -85,7 +97,7 @@ public class MatrixOpTest { res.addElement(v6); instanceOfClass_m3 = classToTest.getDeclaredConstructor(Vector.class).newInstance(res); assertEquals(result, instanceOfClass_m3); -*/ + } } diff --git a/src/test/resources/bytecode/javFiles/MatrixOP.jav b/src/test/resources/bytecode/javFiles/MatrixOP.jav index 828a270bd..0daef9bde 100644 --- a/src/test/resources/bytecode/javFiles/MatrixOP.jav +++ b/src/test/resources/bytecode/javFiles/MatrixOP.jav @@ -18,7 +18,7 @@ public class MatrixOP extends Vector> { } } - mul = (m1, m2) -> { + public mul = (m1, m2) -> { var ret = new MatrixOP(); var i = 0; while(i < size()) {