Flatten generic function types

This commit is contained in:
Daniel Holle 2023-05-24 13:53:23 +02:00
parent 677d68428d
commit 67a582b4a2
9 changed files with 98 additions and 58 deletions

View File

@ -17,7 +17,7 @@ public class Faculty {
public getFact(x) {
public getFact(java.lang.Integer x) {
return fact.apply(x);
}
}

View File

@ -1,8 +1,8 @@
public class Tph2 {
id = x->x;
id3 (x) {
return id.apply(x);
}
id = x->x;
id3 (x) {
return id.apply(x);
}
/*
m(a,b){

View File

@ -1,16 +1,15 @@
package de.dhbwstuttgart.bytecode;
import de.dhbwstuttgart.target.tree.TargetGeneric;
import de.dhbwstuttgart.target.tree.type.TargetGenericType;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetSpecializedType;
import de.dhbwstuttgart.target.tree.type.TargetType;
import de.dhbwstuttgart.target.tree.type.*;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -32,7 +31,24 @@ public class FunNGenerator {
private static final String objectSuperType = Type.getInternalName(Object.class).replace('.','/');
private static final String objectSignature = applySignature(TargetType.Object);
private static String applyDescriptor(TargetType a) { return a.toDescriptor(); }
private static String applyDescriptor(TargetType type, int[] start) {
var res = "L" + type.getInternalName() + "<";
if (type instanceof TargetSpecializedType a)
for (var param : a.params()) {
if (param instanceof TargetGenericType gp) {
res += "TT" + start[0] + ";";
start[0] += 1;
} else {
res += applyDescriptor(param, start);
}
}
else return type.toDescriptor();
res += ">;";
return res;
}
private static String applySignature(TargetType a) { return a.toSignature(); }
private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s;", applySignature(a)); }
@ -68,22 +84,20 @@ public class FunNGenerator {
public static byte[] generateSpecializedBytecode(List<TargetType> argumentTypes, TargetType returnType) {
List<TargetType> parameters = Stream
.concat(argumentTypes.stream(), Stream.of(returnType))
.collect(Collectors.toList());
StringBuilder funNClassSignature = new StringBuilder(objectSignature + applyDescriptor(new TargetRefType(getSuperClassName(argumentTypes.size()), parameters)));
.toList();
var start = new int[]{0};
StringBuilder funNClassSignature = new StringBuilder(objectSignature + applyDescriptor(new TargetRefType(getSuperClassName(argumentTypes.size()), parameters), start));
boolean containsGeneric = false;
String genericSignature = "<";
var generics = new HashSet<TargetGenericType>();
for (TargetType typeArgument : parameters) {
collectGenericTypeArguments(generics, typeArgument);
}
for (var generic : generics) {
genericSignature += String.format("%s:%s", generic.name(), objectSignature);
containsGeneric = true;
}
for (var i = 0; i < start[0]; i++)
genericSignature += String.format("T%d:%s", i, objectSignature);
containsGeneric = true;
genericSignature += ">";
if (containsGeneric) funNClassSignature.insert(0, genericSignature);
System.out.println(funNClassSignature.toString());
ClassWriter classWriter = new ClassWriter(0);
classWriter.visit(bytecodeVersion, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, getSpecializedClassName(argumentTypes, returnType), funNClassSignature.toString(), objectSuperType, new String[]{getSuperClassName(argumentTypes.size())});
@ -91,12 +105,14 @@ public class FunNGenerator {
return classWriter.toByteArray();
}
private static void collectGenericTypeArguments(HashSet<TargetGenericType> generics, TargetType typeArgument) {
private static void collectGenericTypeArguments(Map<TargetGenericType, Integer> generics, TargetType typeArgument) {
if (typeArgument instanceof TargetSpecializedType specializedType) {
for (var arg : specializedType.params())
collectGenericTypeArguments(generics, arg);
} else if (typeArgument instanceof TargetGenericType genericType) {
generics.add(genericType);
if (generics.containsKey(genericType))
generics.put(genericType, generics.get(genericType) + 1);
else generics.put(genericType, 0);
}
}
@ -112,14 +128,6 @@ public class FunNGenerator {
.replace(";", "$_$");
}
public static String getSpecializedDescriptor(List<TargetType> argumentTypes, TargetType returnType) {
return applyDescriptor(new TargetRefType(getSpecializedClassName(argumentTypes, returnType)));
}
public static String getSpecializedSignature(List<TargetType> argumentTypes, TargetType returnType) {
return applySignature(new TargetRefType(getSpecializedClassName(argumentTypes, returnType)));
}
public static List<TargetType> getArguments(List<TargetType> list) {
return list
.stream()

View File

@ -898,7 +898,7 @@ public class JavaTXCompiler {
return generatedClasses;
}
private void writeClassFile(Map<JavaClassName, byte[]> classFiles, File path) throws IOException {
public void writeClassFile(Map<JavaClassName, byte[]> classFiles, File path) throws IOException {
FileOutputStream output;
for (JavaClassName name : classFiles.keySet()) {
byte[] bytecode = classFiles.get(name);

View File

@ -15,6 +15,7 @@ import de.dhbwstuttgart.target.tree.expression.TargetExpression;
import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.result.*;
import java.lang.annotation.Target;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -52,8 +53,7 @@ public class ASTToTargetAST {
}
@Override
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result) {
var referenced = new HashSet<TypePlaceholder>();
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result, Set<TypePlaceholder> referenced) {
eliminateInfima(result, referenced);
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
}
@ -72,8 +72,7 @@ public class ASTToTargetAST {
}
@Override
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result) {
var referenced = new HashSet<TypePlaceholder>();
void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result, Set<TypePlaceholder> referenced) {
eliminateCycles(result, referenced);
eliminateInfima(result, referenced);
eliminateInnerTypeVariablesOfClass(classOrInterface, result, referenced);
@ -523,7 +522,7 @@ public class ASTToTargetAST {
usedTPHsOfMethods.put(method, usedTphs);
eliminateInnerTypeVariables(referenced, result);
addMissingObjectBounds(result, classGenerics);
addMissingObjectBounds(result, classGenerics, usedTphs);
System.out.println(this.getClass().getSimpleName() + " " + method.name + ": " + result);
return result;
@ -582,7 +581,7 @@ public class ASTToTargetAST {
}
}
abstract void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result);
abstract void generics(ClassOrInterface classOrInterface, Set<ResultPair<?, ?>> result, Set<TypePlaceholder> referenced);
Set<ResultPair<?, ?>> generics(ClassOrInterface classOrInterface) {
if (computedGenericsOfClasses.containsKey(classOrInterface))
@ -595,24 +594,31 @@ public class ASTToTargetAST {
findAllBounds(field.getType(), javaResult, equality);
}
var referenced = new HashSet<TypePlaceholder>();
eliminateTransitives(javaResult);
generics(classOrInterface, javaResult);
addMissingObjectBounds(javaResult, null);
generics(classOrInterface, javaResult, referenced);
var referencedByClass = new HashSet<TypePlaceholder>();
for (var field : classOrInterface.getFieldDecl()) {
findTphs(field.getType(), referencedByClass);
}
addMissingObjectBounds(javaResult, null, referencedByClass);
System.out.println(this.getClass().getSimpleName() + " Class " + classOrInterface.getClassName().getClassName() + ": " + javaResult);
return javaResult;
}
void addMissingObjectBounds(Set<ResultPair<?,?>> result, Set<ResultPair<?, ?>> classGenerics) {
outer: for (var p1 : new HashSet<>(result)) {
if (p1 instanceof PairTPHsmallerTPH ptph) {
for (var p2 : new HashSet<>(result)) {
if (ptph.right.equals(p2.getLeft()))
continue outer;
}
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.getLeft().equals(ptph.right)))
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(ptph.right, OBJECT));
void addMissingObjectBounds(Set<ResultPair<?,?>> result, Set<ResultPair<?, ?>> classGenerics, Set<TypePlaceholder> usedTphs) {
outer: for (var tph : usedTphs) {
tph = equality.getOrDefault(tph, tph);
for (var p1 : new HashSet<>(result)) {
if (p1.getLeft().equals(tph)) continue outer;
}
TypePlaceholder finalTph = tph;
if (classGenerics == null || classGenerics.stream().noneMatch((pair) -> pair.getLeft().equals(finalTph)))
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(tph, OBJECT));
}
}
@ -1136,6 +1142,19 @@ public class ASTToTargetAST {
return convert(input, generics.javaGenerics);
}
static TargetType flattenFunNType(List<TargetType> params) {
var newParams = new ArrayList<TargetType>();
for (var i = 0; i < params.size(); i++) {
var param = params.get(i);
if (param instanceof TargetSpecializedType fn) {
newParams.addAll(fn.params());
} else {
newParams.add(param);
}
}
return TargetFunNType.fromParams(params, newParams);
}
protected TargetType convert(RefTypeOrTPHOrWildcardOrGeneric input, GenerateGenerics generics) {
return input.acceptTV(new TypeVisitor<>() {
@Override
@ -1158,7 +1177,7 @@ public class ASTToTargetAST {
var clazz = classLoader.loadClass(code);
auxiliaries.put(clazz.getName(), code);
}
return new TargetFunNType(params.size() - 1, params);
return flattenFunNType(params);
}
return new TargetRefType(name, params);
}

View File

@ -28,6 +28,8 @@ public class GenericsResultSet extends AbstractSet<ResultPair<?, ?>> {
public Optional<ResultPair<?, ?>> getResultPairFor(TypePlaceholder tph) {
var tph2 = equality.getOrDefault(tph, tph);
return this.stream().filter(pair -> pair.getLeft().equals(tph2)).findFirst();
return this.stream().filter(pair -> {
return pair.getLeft().equals(tph2);
}).findFirst();
}
}

View File

@ -4,16 +4,20 @@ import de.dhbwstuttgart.bytecode.FunNGenerator;
import java.util.List;
public record TargetFunNType(int N, List<TargetType> params) implements TargetSpecializedType {
public record TargetFunNType(String name, List<TargetType> params) implements TargetSpecializedType {
@Override
public String getInternalName() {
return FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params));
public static TargetFunNType fromParams(List<TargetType> params) {
return fromParams(params, params);
}
public static TargetFunNType fromParams(List<TargetType> params, List<TargetType> realParams) {
var name = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params));
return new TargetFunNType(name, realParams);
}
@Override
public String name() {
return getInternalName();
public String getInternalName() {
return name;
}
@Override

View File

@ -186,7 +186,13 @@ class TypeToInsertString implements ResultSetVisitor{
@Override
public void visit(TypePlaceholder typePlaceholder) {
insert += ((TypePlaceholder) constraints.getResultPairFor(typePlaceholder).get().getLeft()).getName();
ResultPair<?, ?> resultPair = null;
if (constraints != null)
resultPair = constraints.getResultPairFor(typePlaceholder).orElse(null);
if (resultPair == null)
resultPair = classConstraints.getResultPairFor(typePlaceholder).get();
insert += ((TypePlaceholder)resultPair.getLeft()).getName();
}
@Override

View File

@ -17,6 +17,7 @@ import static org.junit.Assert.*;
import org.objectweb.asm.Opcodes;
import java.io.IOException;
import java.lang.annotation.Target;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
@ -341,7 +342,7 @@ public class TestCodegen {
public void testLambda() throws Exception {
var classLoader = new ByteArrayClassLoader();
//var fun = classLoader.loadClass(Path.of(System.getProperty("user.dir"), "src/test/java/targetast/Fun1$$.class"));
var interfaceType = new TargetFunNType(1, List.of(TargetType.Integer));
var interfaceType = TargetFunNType.fromParams(List.of(TargetType.Integer));
var targetClass = new TargetClass(Opcodes.ACC_PUBLIC, "CGLambda");
targetClass.addConstructor(Opcodes.ACC_PUBLIC, List.of(), new TargetBlock(List.of(