diff --git a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java index 8c60ac42..8a22fd92 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/Codegen.java @@ -1000,7 +1000,7 @@ public class Codegen { private void generateConstructor(TargetConstructor constructor) { MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "", constructor.getDescriptor(), constructor.getSignature(), null); if (constructor.txGenerics() != null) - mv.visitAttribute(new JavaTXSignatureAttribute(cw.newConst(constructor.getTXSignature()))); + mv.visitAttribute(new JavaTXSignatureAttribute(constructor.getTXSignature())); mv.visitCode(); var state = new State(null, mv, 1); @@ -1027,7 +1027,7 @@ public class Codegen { // TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null); if (method.txSignature() != null) { - mv.visitAttribute(new JavaTXSignatureAttribute(cw.newConst(method.getTXSignature()))); + mv.visitAttribute(new JavaTXSignatureAttribute(method.getTXSignature())); } System.out.println(method.getDescriptor()); @@ -1060,7 +1060,7 @@ public class Codegen { clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new) ); if (clazz.txGenerics() != null) - cw.visitAttribute(new JavaTXSignatureAttribute(cw.newConst(generateSignature(clazz, clazz.txGenerics())))); + cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics()))); clazz.fields().forEach(this::generateField); clazz.constructors().forEach(this::generateConstructor); diff --git a/src/main/java/de/dhbwstuttgart/bytecode/JavaTXSignatureAttribute.java b/src/main/java/de/dhbwstuttgart/bytecode/JavaTXSignatureAttribute.java index bd5f6028..ee7b2e57 100644 --- a/src/main/java/de/dhbwstuttgart/bytecode/JavaTXSignatureAttribute.java +++ b/src/main/java/de/dhbwstuttgart/bytecode/JavaTXSignatureAttribute.java @@ -3,10 +3,13 @@ package de.dhbwstuttgart.bytecode; import org.objectweb.asm.*; public class JavaTXSignatureAttribute extends Attribute { - final int signature; + public String signature; - protected JavaTXSignatureAttribute(int signature) { + public JavaTXSignatureAttribute() { super("JavaTXSignature"); + } + protected JavaTXSignatureAttribute(String signature) { + this(); this.signature = signature; } @@ -14,13 +17,14 @@ public class JavaTXSignatureAttribute extends Attribute { protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) { var data = new byte[length]; System.arraycopy(classReader.b, offset, data, 0, length); - return new JavaTXSignatureAttribute(data[0] << 8 | data[1]); + var constantPoolOffset = data[0] << 8 | data[1]; + return new JavaTXSignatureAttribute((String) classReader.readConst(constantPoolOffset, charBuffer)); } @Override protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) { var data = new ByteVector(); - data.putShort(this.signature); + data.putShort(classWriter.newConst(this.signature)); return data; } } diff --git a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java index 79b6d281..a7272806 100644 --- a/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java +++ b/src/main/java/de/dhbwstuttgart/syntaxtree/factory/ASTFactory.java @@ -1,19 +1,16 @@ package de.dhbwstuttgart.syntaxtree.factory; +import java.io.IOException; import java.lang.reflect.*; import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; -import de.dhbwstuttgart.exceptions.NotImplementedException; +import de.dhbwstuttgart.bytecode.JavaTXSignatureAttribute; import de.dhbwstuttgart.parser.NullToken; -import de.dhbwstuttgart.parser.SyntaxTreeGenerator.GenericContext; import de.dhbwstuttgart.parser.scope.JavaClassName; -import de.dhbwstuttgart.parser.scope.JavaClassRegistry; import de.dhbwstuttgart.syntaxtree.Field; import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.type.*; @@ -21,8 +18,11 @@ import de.dhbwstuttgart.syntaxtree.type.Void; import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.statement.Block; import de.dhbwstuttgart.syntaxtree.statement.Statement; -import de.dhbwstuttgart.syntaxtree.type.WildcardType; +import de.dhbwstuttgart.util.Pair; import org.antlr.v4.runtime.Token; +import org.objectweb.asm.*; +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; /** * Anmerkung: @@ -32,21 +32,73 @@ import org.antlr.v4.runtime.Token; public class ASTFactory { public static ClassOrInterface createClass(java.lang.Class jreClass){ + + // TODO Inner classes + + var methodSignatures = new HashMap, String>(); + String classSignature = null; + + // Load class with asm to figure out if there's a JavaTX signature + try { + var bytes = Files.readAllBytes(Path.of(jreClass.getProtectionDomain().getCodeSource().getLocation().getPath())); + var classReader = new ClassReader(bytes); + + var classVisitor = new ClassVisitor(Opcodes.ASM7) { + String classSignature; + @Override + public void visitAttribute(Attribute attribute) { + if (attribute.type.equals("JavaTXSignature")) { + classSignature = ((JavaTXSignatureAttribute) attribute).signature; + } + super.visitAttribute(attribute); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + classSignature = signature; + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + + methodSignatures.put(new Pair<>(name, descriptor), signature); + return new MethodVisitor(Opcodes.ASM7) { + @Override + public void visitAttribute(Attribute attribute) { + if (attribute.type.equals("JavaTXSignature")) { + methodSignatures.put(new Pair<>(name, descriptor), ((JavaTXSignatureAttribute) attribute).signature); + } + super.visitAttribute(attribute); + } + }; + } + }; + + classReader.accept(classVisitor, new Attribute[]{new JavaTXSignatureAttribute()}, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + classSignature = classVisitor.classSignature; + } catch (IOException e) { + // Skip + } + JavaClassName name = new JavaClassName(jreClass.getName()); List methoden = new ArrayList<>(); List konstruktoren = new ArrayList<>(); for(java.lang.reflect.Constructor constructor : jreClass.getConstructors()){ - createConstructor(constructor, jreClass).map(c -> konstruktoren.add(c)); + var signature = methodSignatures.get(new Pair<>(constructor.getName(), org.objectweb.asm.Type.getConstructorDescriptor(constructor))); + createConstructor(constructor, signature, jreClass).map(c -> konstruktoren.add(c)); } Set allMethods = new HashSet<>(Arrays.asList(jreClass.getMethods())); Set allDeclaredMethods = new HashSet<>(Arrays.asList(jreClass.getDeclaredMethods())); Set allInheritedMethods = new HashSet<>(allMethods); allInheritedMethods.removeAll(allDeclaredMethods); for(java.lang.reflect.Method method : allDeclaredMethods){ - methoden.add(createMethod(method, jreClass, false)); + var signature = methodSignatures.get(new Pair<>(method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method))); + methoden.add(createMethod(method, signature, jreClass, false)); } for(java.lang.reflect.Method method : allInheritedMethods){ - methoden.add(createMethod(method, jreClass, true)); + var signature = methodSignatures.get(new Pair<>(method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method))); + methoden.add(createMethod(method, signature, jreClass, true)); } List felder = new ArrayList<>(); for(java.lang.reflect.Field field : jreClass.getDeclaredFields()){ @@ -72,7 +124,8 @@ public class ASTFactory { for(Type jreInterface : jreClass.getGenericInterfaces()){ implementedInterfaces.add((RefType) createType(jreInterface)); } - GenericDeclarationList genericDeclarationList = createGenerics(jreClass.getTypeParameters(), jreClass, null); + + GenericDeclarationList genericDeclarationList = createGenerics(classSignature, jreClass, null); Token offset = new NullToken(); //Braucht keinen Offset, da diese Klasse nicht aus einem Quellcode geparst wurde @@ -87,7 +140,7 @@ public class ASTFactory { // return createClass(classType).getType(); //} - private static Optional createConstructor(Constructor constructor, Class inClass) { + private static Optional createConstructor(Constructor constructor, String signature, Class inClass) { String name = constructor.getName(); RefTypeOrTPHOrWildcardOrGeneric returnType = createType(inClass); Parameter[] jreParams = constructor.getParameters(); @@ -101,7 +154,7 @@ public class ASTFactory { } ParameterList parameterList = new ParameterList(params, new NullToken()); Block block = new Block(new ArrayList(), new NullToken()); - GenericDeclarationList gtvDeclarations = createGenerics(constructor.getTypeParameters(), inClass, constructor.getName()); + GenericDeclarationList gtvDeclarations = createGenerics(signature, inClass, constructor.getName()); Token offset = new NullToken(); int modifier = constructor.getModifiers(); @@ -112,7 +165,7 @@ public class ASTFactory { return Optional.of(new de.dhbwstuttgart.syntaxtree.Constructor(modifier, name,returnType, parameterList, block, gtvDeclarations, offset /*, new ArrayList<>() geloescht PL 2018-11-24 */)); } - public static Method createMethod(java.lang.reflect.Method jreMethod, java.lang.Class inClass, Boolean isInherited){ + public static Method createMethod(java.lang.reflect.Method jreMethod, String signature, java.lang.Class inClass, Boolean isInherited){ String name = jreMethod.getName(); RefTypeOrTPHOrWildcardOrGeneric returnType; Type jreRetType; @@ -133,18 +186,53 @@ public class ASTFactory { } ParameterList parameterList = new ParameterList(params, new NullToken()); Block block = new Block(new ArrayList(), new NullToken()); - GenericDeclarationList gtvDeclarations = createGenerics(jreMethod.getTypeParameters(), inClass, jreMethod.getName()); + GenericDeclarationList gtvDeclarations = createGenerics(signature, inClass, jreMethod.getName()); Token offset = new NullToken(); return new Method(jreMethod.getModifiers(), name,returnType, parameterList, block, gtvDeclarations, offset, isInherited); } - public static GenericDeclarationList createGenerics(TypeVariable[] typeParameters, Class context, String methodName){ - List gtvs = new ArrayList<>(); - for(TypeVariable jreTV : typeParameters){ - de.dhbwstuttgart.syntaxtree.GenericTypeVar gtv = createGeneric(jreTV, jreTV.getName(), context, methodName); - gtvs.add(gtv); - } + public static GenericDeclarationList createGenerics(String signature, Class context, String methodName){ + var gtvs = new ArrayList(); + var signatureVisitor = new SignatureVisitor(Opcodes.ASM7) { + List bounds = new ArrayList<>(); + Stack bound = new Stack<>(); + + @Override + public void visitFormalTypeParameter(String name) { + bounds = new ArrayList<>(); + gtvs.add(new GenericTypeVar(name, bounds, new NullToken(), new NullToken())); + } + + @Override + public void visitTypeVariable(String name) { + ((RefType) bound.peek()).getParaList().add(new GenericRefType(name, new NullToken())); + } + + @Override + public void visitClassType(String name) { + var currentBound = new RefType(new JavaClassName(name), new ArrayList<>(), new NullToken()); + bound.push(currentBound); + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + return this; + } + + @Override + public void visitEnd() { + var last = bound.pop(); + if (bound.empty()) bounds.add(last); + else { + ((RefType) bound.peek()).getParaList().add(last); + } + } + }; + + var sr = new SignatureReader(signature); + sr.accept(signatureVisitor); + return new GenericDeclarationList(gtvs,new NullToken()); } diff --git a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java index 3ebd5430..ede06693 100644 --- a/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java +++ b/src/main/java/de/dhbwstuttgart/target/generate/ASTToTargetAST.java @@ -16,6 +16,7 @@ import de.dhbwstuttgart.target.tree.expression.TargetExpression; import de.dhbwstuttgart.target.tree.type.*; import de.dhbwstuttgart.typeinference.constraints.Pair; import de.dhbwstuttgart.typeinference.result.*; +import org.objectweb.asm.Attribute; import java.util.*; import java.util.stream.Collectors;