diff --git a/src/de/dhbwstuttgart/bytecode/BytecodeGen.java b/src/de/dhbwstuttgart/bytecode/BytecodeGen.java index f9bf72ed7..5115a29bd 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; @@ -43,6 +45,8 @@ public class BytecodeGen implements ASTVisitor { private ResultSet resultSet; private int indexOfFirstParam = 0; + private String superClass; + // stores parameter, local vars and the next index on the local variable table, which use for aload_i, astore_i,... HashMap paramsAndLocals = new HashMap<>(); // stores generics and their bounds of class @@ -50,6 +54,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 +97,7 @@ public class BytecodeGen implements ASTVisitor { @Override public void visit(ClassOrInterface classOrInterface) { + className = classOrInterface.getClassName().toString(); cw.visitSource(className +".jav", null); @@ -97,27 +105,42 @@ 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) { + superClass = classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()); 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 +156,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); @@ -156,7 +209,7 @@ public class BytecodeGen implements ASTVisitor { desc = constructor.accept(new DescriptorToString(resultSet)); MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", desc, sig, null); mv.visitCode(); - BytecodeGenMethod gen = new BytecodeGenMethod(className,resultSet,field, mv,paramsAndLocals,cw, + BytecodeGenMethod gen = new BytecodeGenMethod(className,superClass,resultSet,field, mv,paramsAndLocals,cw, genericsAndBoundsMethod,genericsAndBounds,isInterface,classFiles); if(!field.getParameterList().iterator().hasNext()) { mv.visitInsn(Opcodes.RETURN); @@ -215,11 +268,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); + 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)); @@ -227,7 +287,7 @@ public class BytecodeGen implements ASTVisitor { MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+acc, method.getName(), methDesc, sig, null); mv.visitCode(); - BytecodeGenMethod gen = new BytecodeGenMethod(className,resultSet,method, mv,paramsAndLocals,cw, + BytecodeGenMethod gen = new BytecodeGenMethod(className,superClass,resultSet,method, mv,paramsAndLocals,cw, genericsAndBoundsMethod,genericsAndBounds,isInterface,classFiles); mv.visitMaxs(0, 0); @@ -475,5 +535,49 @@ public class BytecodeGen implements ASTVisitor { public void visit(UnaryExpr unaryExpr) { throw new NotImplementedException(); } + + 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) { + 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 genericsAndBoundsMethod; + private HashMap genericsAndBoundsMethod; private HashMap genericsAndBounds; private boolean isBinaryExp = false; - + private String superClass; + private IStatement statement = null; // for tests ** @@ -67,11 +71,12 @@ public class BytecodeGenMethod implements StatementVisitor { private ArrayList varsFunInterface = new ArrayList<>();; - public BytecodeGenMethod(String className, ResultSet resultSet, Method m, MethodVisitor mv, + public BytecodeGenMethod(String className, String superClass,ResultSet resultSet, Method m, MethodVisitor mv, HashMap paramsAndLocals, ClassWriter cw, HashMap genericsAndBoundsMethod, HashMap genericsAndBounds, boolean isInterface, HashMap classFiles) { this.className = className; + this.superClass = superClass; this.resultSet = resultSet; this.m = m; this.mv = mv; @@ -104,7 +109,11 @@ public class BytecodeGenMethod implements StatementVisitor { } lambdaExpression.methodBody.accept(this); } - + + public void isBinary(boolean isBinary) { + this.isBinaryExp =isBinary; + } + private String getResolvedType(RefTypeOrTPHOrWildcardOrGeneric type) { return resultSet.resolveType(type).resolvedType.acceptTV(new TypeToDescriptor()); } @@ -120,7 +129,7 @@ public class BytecodeGenMethod implements StatementVisitor { public void visit(SuperCall superCall) { superCall.receiver.accept(this); superCall.arglist.accept(this); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), superCall.name, "()V", + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, this.superClass, superCall.name, "()V", isInterface); } @@ -167,6 +176,11 @@ public class BytecodeGenMethod implements StatementVisitor { doBoxing(binaryType); isBinaryExp = false; } + System.out.println("ASSIGN TYPE R: " + getResolvedType(assign.rightSide.getType())); + String typeOfRightSide = getResolvedType(assign.rightSide.getType()); + if(typeOfRightSide.contains("<")) { + mv.visitTypeInsn(Opcodes.CHECKCAST, typeOfRightSide.substring(0, typeOfRightSide.indexOf('<'))); + } assign.lefSide.accept(this); statement = null; @@ -621,14 +635,15 @@ public class BytecodeGenMethod implements StatementVisitor { @Override public void visit(MethodCall methodCall) { - + + System.out.println("Methodcall type : " + resultSet.resolveType(methodCall.getType()).resolvedType.acceptTV(new TypeToDescriptor())); methodCall.receiver.accept(this); methodCall.arglist.accept(this); MethodFromMethodCall method = new MethodFromMethodCall(methodCall.arglist, methodCall.getType(), genericsAndBoundsMethod, genericsAndBounds); String mDesc = method.accept(new DescriptorToString(resultSet)); - + System.out.println("Methodcall Desc : " + mDesc); // is methodCall.receiver functional Interface)? if (varsFunInterface.contains(methodCall.receiver.getType())) { mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, getResolvedType(methodCall.receiver.getType()), methodCall.name, @@ -641,6 +656,9 @@ public class BytecodeGenMethod implements StatementVisitor { // if(!methodCall.getType().toString().equals("V")) { // mv.visitInsn(Opcodes.POP); // } + if(isBinaryExp) { + doUnboxing(getResolvedType(methodCall.getType())); + } } @Override @@ -799,7 +817,7 @@ public class BytecodeGenMethod implements StatementVisitor { statement = new LoopStmt(whileStmt.expr, whileStmt.loopBlock); isBinaryExp = statement.isExprBinary(); whileStmt.expr.accept(this); - isBinaryExp = false; +// isBinaryExp = false; statement = null; } @@ -1040,13 +1058,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/LoopStmt.java b/src/de/dhbwstuttgart/bytecode/LoopStmt.java index 109efd345..0f7788d47 100644 --- a/src/de/dhbwstuttgart/bytecode/LoopStmt.java +++ b/src/de/dhbwstuttgart/bytecode/LoopStmt.java @@ -18,6 +18,7 @@ public class LoopStmt extends AStatement { @Override public void genBCForRelOp(MethodVisitor mv,Label branchLabel, Label endLabel, BytecodeGenMethod bytecodeGenMethod) { + bytecodeGenMethod.isBinary(false); this.loopBlock.accept(bytecodeGenMethod); mv.visitJumpInsn(Opcodes.GOTO, endLabel); mv.visitLabel(branchLabel); diff --git a/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java b/src/de/dhbwstuttgart/bytecode/descriptor/DescriptorToString.java index 0e97ca4c3..b22109c16 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+ ";"; } @@ -141,26 +145,34 @@ public class DescriptorToString implements DescriptorVisitor{ public String visit(MethodFromMethodCall methodFromMethodCall) { 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)+ ";"; + String d = resultSet.resolveType(e.getType()).resolvedType.acceptTV(new TypeToDescriptor()); + + if(d.substring(0, 4).equals("TPH ") ||d.contains("<")) { + 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")) { + String retType = resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); + System.out.println("DescriptorToString retType = " + retType); + if(retType.equals("void")) { desc += ")V"; + }else if(retType.substring(0, 4).equals("TPH ")|| retType.contains("<")){ + desc += ")L"+Type.getInternalName(Object.class)+ ";"; }else { - String ret = resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor()); - if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(ret)) { - desc += ")L"+methodFromMethodCall.getGenericsAndBoundsMethod().get(ret)+ ";"; - }else if(methodFromMethodCall.getGenericsAndBounds().containsKey(ret)){ - desc += ")L"+methodFromMethodCall.getGenericsAndBounds().get(ret)+ ";"; + if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(retType)) { + desc += ")L"+methodFromMethodCall.getGenericsAndBoundsMethod().get(retType)+ ";"; + }else if(methodFromMethodCall.getGenericsAndBounds().containsKey(retType)){ + desc += ")L"+methodFromMethodCall.getGenericsAndBounds().get(retType)+ ";"; }else { - desc += ")" + "L"+resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";"; + desc += ")" + "L"+retType+ ";"; } } // desc = addReturnType(desc, methodFromMethodCall.getReturnType(), resultSet); diff --git a/src/de/dhbwstuttgart/bytecode/descriptor/TypeToDescriptor.java b/src/de/dhbwstuttgart/bytecode/descriptor/TypeToDescriptor.java index 69ac6d137..8ee843289 100644 --- a/src/de/dhbwstuttgart/bytecode/descriptor/TypeToDescriptor.java +++ b/src/de/dhbwstuttgart/bytecode/descriptor/TypeToDescriptor.java @@ -19,7 +19,9 @@ public class TypeToDescriptor implements TypeVisitor{ @Override public String visit(SuperWildcardType superWildcardType) { - throw new NotImplementedException(); + System.out.println("\nWILDCARD ="+superWildcardType.getInnerType().toString().replace(".", "/")); + return superWildcardType.getInnerType().toString().replace(".", "/"); + //throw new NotImplementedException(); } @Override @@ -29,6 +31,7 @@ public class TypeToDescriptor implements TypeVisitor{ @Override public String visit(ExtendsWildcardType extendsWildcardType) { + System.out.println("\nWILDCARD extends ="+extendsWildcardType.getInnerType().toString().replace(".", "/")); return extendsWildcardType.getInnerType().toString().replace(".", "/"); //throw new NotImplementedException(); } diff --git a/src/de/dhbwstuttgart/bytecode/signature/Signature.java b/src/de/dhbwstuttgart/bytecode/signature/Signature.java index 488046619..51329a55f 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,10 +30,13 @@ public class Signature { private Method method; private HashMap methodParamsAndTypes; private ResultSet resultSet; + 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(); } @@ -42,12 +49,14 @@ public class Signature { createSignatureForConsOrMethod(this.constructor,true); } - public Signature(Method method, HashMap genericsAndBoundsMethod, - HashMap methodParamsAndTypes, ResultSet resultSet) { + 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.methodPairs = methodPairs; sw = new SignatureWriter(); createSignatureForConsOrMethod(this.method,false); } @@ -92,28 +101,62 @@ 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 ")) { 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(); + 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 ") && !genericsAndBoundsMethod.containsKey(pT)) { + if(pT.substring(0,4).equals("TPH ")) { 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(); + 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); + } } + +// 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); +// } +// }); } // visit each method-parameter to create the signature @@ -125,15 +168,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); @@ -194,7 +228,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 000000000..99ec31630 --- /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/FacTest.java b/test/bytecode/FacTest.java index 0875db05c..c4cab24e5 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/Tph2Test.java b/test/bytecode/Tph2Test.java new file mode 100644 index 000000000..4cda41484 --- /dev/null +++ b/test/bytecode/Tph2Test.java @@ -0,0 +1,41 @@ +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 Tph2Test { + + 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/Tph2.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("Tph2"); + instanceOfClass = classToTest.getDeclaredConstructor().newInstance(); + } + + @Test + public void test() { + fail("Not yet implemented"); + } + +} diff --git a/test/bytecode/TphTest.java b/test/bytecode/TphTest.java new file mode 100644 index 000000000..449db765d --- /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/Faculty.jav b/test/bytecode/javFiles/Faculty.jav index cea028c1a..a5c649b88 100644 --- a/test/bytecode/javFiles/Faculty.jav +++ b/test/bytecode/javFiles/Faculty.jav @@ -2,14 +2,15 @@ import java.lang.Integer; class Faculty { - Integer mul(Integer x, Integer y) { - return x; - } - m () { var fact = (Integer x) -> { - return mul(x, x); + if (x == 1) { + return x; + } + else { + return x * fact.apply(x-1); + } }; return fact; } diff --git a/test/bytecode/javFiles/IfTest.jav b/test/bytecode/javFiles/IfTest.jav index 806e21578..33f9ecba8 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/Lambda.jav b/test/bytecode/javFiles/Lambda.jav index 3aeded259..de4342719 100644 --- a/test/bytecode/javFiles/Lambda.jav +++ b/test/bytecode/javFiles/Lambda.jav @@ -6,6 +6,6 @@ public class Lambda { var lam1 = (Integer x) -> { return x; }; - return lam1; + return lam1.apply(1); } } diff --git a/test/bytecode/javFiles/Matrix.jav b/test/bytecode/javFiles/Matrix.jav index 80f41b163..f0ea03563 100644 --- a/test/bytecode/javFiles/Matrix.jav +++ b/test/bytecode/javFiles/Matrix.jav @@ -2,24 +2,24 @@ import java.util.Vector; import java.lang.Integer; import java.lang.Boolean; -class Matrix extends Vector> { +public class Matrix extends Vector> { mul(m) { var ret = new Matrix(); var i = 0; while(i < size()) { -// var v1 = this.elementAt(i); -// var v2 = new Vector(); -// var j = 0; -// while(j < v1.size()) { + var v1 = this.elementAt(i); + var v2 = new Vector(); + var j = 0; + while(j < v1.size()) { // var erg = 0; -// var k = 0; -// while(k < v1.size()) { + // var k = 0; + // while(k < v1.size()) { // erg = erg + v1.elementAt(k) -// * m.elementAt(k).elementAt(j); -// k++; } -// v2.addElement(new Integer(erg)); -// j++; } -// ret.addElement(v2); + // * m.elementAt(k).elementAt(j); + // k++; } + // v2.addElement(new Integer(erg)); + j++; } + ret.addElement(v2); i++; } return ret; diff --git a/test/bytecode/javFiles/Tph.jav b/test/bytecode/javFiles/Tph.jav new file mode 100644 index 000000000..3f9d0aab3 --- /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 diff --git a/test/bytecode/javFiles/Tph2.jav b/test/bytecode/javFiles/Tph2.jav new file mode 100644 index 000000000..c957eae6e --- /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 diff --git a/test/javFiles/Lambda.jav b/test/javFiles/Lambda.jav index 553dc496a..02e8b51bf 100644 --- a/test/javFiles/Lambda.jav +++ b/test/javFiles/Lambda.jav @@ -7,7 +7,7 @@ public class Lambda { var lam1 = (x) -> { return x; }; - return lam1; + return lam1.apply(1); } } diff --git a/test/typeinference/UnifyTest.java b/test/typeinference/UnifyTest.java index 2a496166b..995890ab6 100644 --- a/test/typeinference/UnifyTest.java +++ b/test/typeinference/UnifyTest.java @@ -29,12 +29,12 @@ public class UnifyTest { execute(new File(rootDirectory+"fc.jav")); } */ -/* + @Test public void lambda() throws IOException, ClassNotFoundException { execute(new File(rootDirectory+"Lambda.jav")); } -*/ + /* @Test public void lambda2() throws IOException, ClassNotFoundException { @@ -74,6 +74,7 @@ public class UnifyTest { } */ + /* @Test public void matrix() throws IOException, ClassNotFoundException { @@ -81,6 +82,7 @@ public class UnifyTest { //JavaTXCompiler compiler = new JavaTXCompiler(new File(rootDirectory+"Matrix.jav")); //compiler.generateBytecode(); } + */ /* @Test