Start working on a JavaTX signature attribute
This commit is contained in:
parent
24bbce8265
commit
a92172c9da
@ -1,2 +1,24 @@
|
|||||||
package de.dhbwstuttgart.bytecode;public class JavaTXSignatureAttribute {
|
package de.dhbwstuttgart.bytecode;
|
||||||
|
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
public class JavaTXSignatureAttribute extends Attribute {
|
||||||
|
final String signature;
|
||||||
|
|
||||||
|
protected JavaTXSignatureAttribute(String signature) {
|
||||||
|
super("JavaTXSignature");
|
||||||
|
this.signature = signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) {
|
||||||
|
return super.read(classReader, offset, length, charBuffer, codeAttributeOffset, labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteVector write(ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) {
|
||||||
|
var data = new ByteVector();
|
||||||
|
data.putUTF8(this.signature);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,12 @@ public class ASTToTargetAST {
|
|||||||
return all.stream().map(GenericsResult::new).toList();
|
return all.stream().map(GenericsResult::new).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record Generics(Set<ResultPair<?, ?>> javaGenerics, Set<ResultPair<?, ?>> txGenerics) {}
|
||||||
|
|
||||||
class Sigma {
|
class Sigma {
|
||||||
Map<Method, Set<ResultPair<?, ?>>> computedGenericsOfMethods = new HashMap<>();
|
Map<Method, Generics> computedGenericsOfMethods = new HashMap<>();
|
||||||
|
Map<ClassOrInterface, Generics> computedGenericsOfClasses = new HashMap<>();
|
||||||
Map<Method, Set<TypePlaceholder>> usedTPHsOfMethods = new HashMap<>();
|
Map<Method, Set<TypePlaceholder>> usedTPHsOfMethods = new HashMap<>();
|
||||||
Map<ClassOrInterface, Set<ResultPair<?, ?>>> computedGenericsOfClasses = new HashMap<>();
|
|
||||||
|
|
||||||
Set<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
|
Set<PairTPHsmallerTPH> simplifiedConstraints = new HashSet<>();
|
||||||
Map<TypePlaceholder, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
|
Map<TypePlaceholder, RefTypeOrTPHOrWildcardOrGeneric> concreteTypes = new HashMap<>();
|
||||||
@ -134,14 +136,16 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Family of generated Generics
|
// Family of generated Generics
|
||||||
Set<ResultPair<?, ?>> generics(ClassOrInterface owner, Method method) {
|
Generics generics(ClassOrInterface owner, Method method) {
|
||||||
if (computedGenericsOfMethods.containsKey(method))
|
if (computedGenericsOfMethods.containsKey(method))
|
||||||
return computedGenericsOfMethods.get(method);
|
return computedGenericsOfMethods.get(method);
|
||||||
|
|
||||||
Set<ResultPair<?, ?>> result = new HashSet<>();
|
Set<ResultPair<?, ?>> txResult = new HashSet<>();
|
||||||
computedGenericsOfMethods.put(method, result);
|
Set<ResultPair<?, ?>> javaResult = new HashSet<>();
|
||||||
|
var generics = new Generics(javaResult, txResult);
|
||||||
|
computedGenericsOfMethods.put(method, generics);
|
||||||
|
|
||||||
var genericsOfClass = generics(owner);
|
var genericsOfClass = generics(owner).txGenerics();
|
||||||
var simplifiedConstraints = new HashSet<>(this.simplifiedConstraints);
|
var simplifiedConstraints = new HashSet<>(this.simplifiedConstraints);
|
||||||
|
|
||||||
HashSet<TypePlaceholder> typeVariables = new HashSet<>();
|
HashSet<TypePlaceholder> typeVariables = new HashSet<>();
|
||||||
@ -178,7 +182,7 @@ public class ASTToTargetAST {
|
|||||||
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
||||||
for (var pair : simplifiedConstraints) {
|
for (var pair : simplifiedConstraints) {
|
||||||
if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) {
|
if (pair.left.equals(typeVariable) && typeVariables.contains(pair.right)) {
|
||||||
addToPairs(result, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right)));
|
addToPairs(txResult, new PairTPHsmallerTPH(pair.left, equality.getOrDefault(pair.right, pair.right)));
|
||||||
typeVariables.add(pair.right);
|
typeVariables.add(pair.right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,7 +201,7 @@ public class ASTToTargetAST {
|
|||||||
methodCall.getArgumentList()
|
methodCall.getArgumentList()
|
||||||
.getArguments()
|
.getArguments()
|
||||||
.stream()
|
.stream()
|
||||||
.map(x -> x.getType())
|
.map(TypableStatement::getType)
|
||||||
.collect(Collectors.toCollection(HashSet::new))
|
.collect(Collectors.toCollection(HashSet::new))
|
||||||
.stream().filter(x -> x instanceof TypePlaceholder)
|
.stream().filter(x -> x instanceof TypePlaceholder)
|
||||||
.map(tph -> equality.getOrDefault(tph, (TypePlaceholder) tph))
|
.map(tph -> equality.getOrDefault(tph, (TypePlaceholder) tph))
|
||||||
@ -221,7 +225,7 @@ public class ASTToTargetAST {
|
|||||||
if (optMethod.isEmpty()) return;
|
if (optMethod.isEmpty()) return;
|
||||||
var method = optMethod.get();
|
var method = optMethod.get();
|
||||||
|
|
||||||
var generics = generics(owner, method);
|
var generics = generics(owner, method).txGenerics();
|
||||||
|
|
||||||
// transitive and
|
// transitive and
|
||||||
var all = transitiveClosure(generics);
|
var all = transitiveClosure(generics);
|
||||||
@ -256,8 +260,8 @@ public class ASTToTargetAST {
|
|||||||
var newPair = new PairTPHsmallerTPH(tph, tph2);
|
var newPair = new PairTPHsmallerTPH(tph, tph2);
|
||||||
newPairs.add(newPair);
|
newPairs.add(newPair);
|
||||||
|
|
||||||
if (!containsRelation(result, newPair))
|
if (!containsRelation(txResult, newPair))
|
||||||
addToPairs(result, newPair);
|
addToPairs(txResult, newPair);
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,18 +474,18 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (minimalPair != null)
|
if (minimalPair != null)
|
||||||
addToPairs(result, minimalPair);
|
addToPairs(txResult, minimalPair);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All unbounded type variables (bounds not in method)
|
// All unbounded type variables (bounds not in method)
|
||||||
outer:
|
outer:
|
||||||
for (var typeVariable : typeVariables) {
|
for (var typeVariable : typeVariables) {
|
||||||
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
if (typeVariablesOfClass.contains(typeVariable)) continue;
|
||||||
for (var pair : result) {
|
for (var pair : txResult) {
|
||||||
if (pair.getLeft().equals(typeVariable))
|
if (pair.getLeft().equals(typeVariable))
|
||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT));
|
addToPairs(txResult, new PairTPHequalRefTypeOrWildcardType(typeVariable, OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
// All unbounded bounds
|
// All unbounded bounds
|
||||||
@ -492,10 +496,14 @@ public class ASTToTargetAST {
|
|||||||
continue outer;
|
continue outer;
|
||||||
}
|
}
|
||||||
if (!typeVariablesOfClass.contains(pair.right) && typeVariables.contains(pair.right)) {
|
if (!typeVariablesOfClass.contains(pair.right) && typeVariables.contains(pair.right)) {
|
||||||
addToPairs(result, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
addToPairs(txResult, new PairTPHequalRefTypeOrWildcardType(pair.right, OBJECT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eliminateCyclesAndInfima(result);
|
|
||||||
|
javaResult.addAll(txResult); // Same result until here
|
||||||
|
eliminateCycles(javaResult);
|
||||||
|
eliminateInfima(javaResult);
|
||||||
|
eliminateInfima(txResult);
|
||||||
|
|
||||||
// For eliminating inner type variables we need to figure out which ones are actually used
|
// For eliminating inner type variables we need to figure out which ones are actually used
|
||||||
// TODO Maybe don't do this twice?
|
// TODO Maybe don't do this twice?
|
||||||
@ -507,13 +515,16 @@ public class ASTToTargetAST {
|
|||||||
var referenced = new HashSet<>(usedTphs);
|
var referenced = new HashSet<>(usedTphs);
|
||||||
referenced.addAll(typeVariablesOfClass);
|
referenced.addAll(typeVariablesOfClass);
|
||||||
|
|
||||||
eliminateInnerTypeVariables(referenced, result);
|
eliminateInnerTypeVariables(referenced, javaResult);
|
||||||
|
eliminateInnerTypeVariables(referenced, txResult);
|
||||||
|
|
||||||
usedTPHsOfMethods.put(method, usedTphs);
|
usedTPHsOfMethods.put(method, usedTphs);
|
||||||
|
|
||||||
System.out.println(method.name + ": " + result);
|
equalizeTypeVariables(javaResult);
|
||||||
|
|
||||||
return result;
|
System.out.println(method.name + ": " + txResult + " & " + javaResult);
|
||||||
|
|
||||||
|
return generics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<ResultPair<?, ?>> generics) {
|
void findAllBounds(RefTypeOrTPHOrWildcardOrGeneric type, Set<ResultPair<?, ?>> generics) {
|
||||||
@ -546,21 +557,29 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ResultPair<?, ?>> generics(ClassOrInterface classOrInterface) {
|
Generics generics(ClassOrInterface classOrInterface) {
|
||||||
if (computedGenericsOfClasses.containsKey(classOrInterface))
|
if (computedGenericsOfClasses.containsKey(classOrInterface))
|
||||||
return computedGenericsOfClasses.get(classOrInterface);
|
return computedGenericsOfClasses.get(classOrInterface);
|
||||||
|
|
||||||
Set<ResultPair<?, ?>> result = new HashSet<>();
|
Set<ResultPair<?, ?>> txResult = new HashSet<>();
|
||||||
for (var field : classOrInterface.getFieldDecl()) {
|
Set<ResultPair<?, ?>> javaResult = new HashSet<>();
|
||||||
findAllBounds(field.getType(), result);
|
var generics = new Generics(javaResult, txResult);
|
||||||
}
|
|
||||||
computedGenericsOfClasses.put(classOrInterface, result);
|
|
||||||
eliminateCyclesAndInfima(result);
|
|
||||||
eliminateInnerTypeVariablesOfClass(classOrInterface, result);
|
|
||||||
equalizeTypeVariables(result);
|
|
||||||
|
|
||||||
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + result);
|
for (var field : classOrInterface.getFieldDecl()) {
|
||||||
return result;
|
findAllBounds(field.getType(), txResult);
|
||||||
|
}
|
||||||
|
computedGenericsOfClasses.put(classOrInterface, generics);
|
||||||
|
|
||||||
|
javaResult.addAll(txResult);
|
||||||
|
eliminateCycles(javaResult);
|
||||||
|
eliminateInfima(txResult);
|
||||||
|
eliminateInfima(javaResult);
|
||||||
|
eliminateInnerTypeVariablesOfClass(classOrInterface, txResult);
|
||||||
|
eliminateInnerTypeVariablesOfClass(classOrInterface, javaResult);
|
||||||
|
equalizeTypeVariables(javaResult);
|
||||||
|
|
||||||
|
System.out.println("Class " + classOrInterface.getClassName().getClassName() + ": " + txResult);
|
||||||
|
return generics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void equalizeTypeVariables(Set<ResultPair<?, ?>> input) {
|
void equalizeTypeVariables(Set<ResultPair<?, ?>> input) {
|
||||||
@ -707,11 +726,6 @@ public class ASTToTargetAST {
|
|||||||
} while (foundInfima);
|
} while (foundInfima);
|
||||||
}
|
}
|
||||||
|
|
||||||
void eliminateCyclesAndInfima(Set<ResultPair<?, ?>> input) {
|
|
||||||
eliminateCycles(input);
|
|
||||||
eliminateInfima(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
RefTypeOrTPHOrWildcardOrGeneric getType(RefTypeOrTPHOrWildcardOrGeneric type) {
|
RefTypeOrTPHOrWildcardOrGeneric getType(RefTypeOrTPHOrWildcardOrGeneric type) {
|
||||||
if (type instanceof TypePlaceholder tph) {
|
if (type instanceof TypePlaceholder tph) {
|
||||||
if (equality.containsKey(tph)) {
|
if (equality.containsKey(tph)) {
|
||||||
@ -888,14 +902,14 @@ public class ASTToTargetAST {
|
|||||||
var genericsIter = input.getGenerics().iterator();
|
var genericsIter = input.getGenerics().iterator();
|
||||||
if (genericsIter.hasNext()) {
|
if (genericsIter.hasNext()) {
|
||||||
// Add empty set of generics to cache so that it doesn't try to calculate it later
|
// Add empty set of generics to cache so that it doesn't try to calculate it later
|
||||||
sigma.computedGenericsOfClasses.put(input, new HashSet<>());
|
sigma.computedGenericsOfClasses.put(input, new Generics(new HashSet<>(), new HashSet<>()));
|
||||||
while (genericsIter.hasNext()) {
|
while (genericsIter.hasNext()) {
|
||||||
var next = genericsIter.next();
|
var next = genericsIter.next();
|
||||||
generics.addAll(convert(next));
|
generics.addAll(convert(next));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Generate generics only if there are no user defined ones
|
// Generate generics only if there are no user defined ones
|
||||||
generics = convert(sigma.generics(input));
|
generics = convert(sigma.generics(input).javaGenerics());
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetBlock fieldInitializer = null;
|
TargetBlock fieldInitializer = null;
|
||||||
@ -956,7 +970,7 @@ public class ASTToTargetAST {
|
|||||||
var generics = sigma.generics(currentClass, input);
|
var generics = sigma.generics(currentClass, input);
|
||||||
List<MethodParameter> params = convert(input.getParameterList());
|
List<MethodParameter> params = convert(input.getParameterList());
|
||||||
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
||||||
var convertedGenerics = collectMethodGenerics(generics, input);
|
var convertedGenerics = collectMethodGenerics(generics.javaGenerics(), input);
|
||||||
result.add(new TargetConstructor(input.modifier, convertedGenerics, params, convert(input.block), fieldInitializer));
|
result.add(new TargetConstructor(input.modifier, convertedGenerics, params, convert(input.block), fieldInitializer));
|
||||||
parameterSet.add(params);
|
parameterSet.add(params);
|
||||||
}
|
}
|
||||||
@ -975,7 +989,7 @@ public class ASTToTargetAST {
|
|||||||
var generics = sigma.generics(currentClass, input);
|
var generics = sigma.generics(currentClass, input);
|
||||||
List<MethodParameter> params = convert(input.getParameterList());
|
List<MethodParameter> params = convert(input.getParameterList());
|
||||||
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
|
||||||
var convertedGenerics = collectMethodGenerics(generics, input);
|
var convertedGenerics = collectMethodGenerics(generics.javaGenerics(), input);
|
||||||
result.add(new TargetMethod(
|
result.add(new TargetMethod(
|
||||||
input.modifier,
|
input.modifier,
|
||||||
input.name, convertedGenerics, params,
|
input.name, convertedGenerics, params,
|
||||||
|
@ -16,11 +16,16 @@ public class GenericsResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Set<ResultPair<?, ?>> get(ClassOrInterface clazz) {
|
public Set<ResultPair<?, ?>> get(ClassOrInterface clazz) {
|
||||||
return this.sigma.computedGenericsOfClasses.getOrDefault(clazz, Set.of());
|
var generics = this.sigma.computedGenericsOfClasses.get(clazz);
|
||||||
|
if (generics == null) return Set.of();
|
||||||
|
return generics.txGenerics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Compute generics if not present?
|
||||||
public Set<ResultPair<?, ?>> get(Method method) {
|
public Set<ResultPair<?, ?>> get(Method method) {
|
||||||
return this.sigma.computedGenericsOfMethods.getOrDefault(method, Set.of());
|
var generics = this.sigma.computedGenericsOfMethods.get(method);
|
||||||
|
if (generics == null) return Set.of();
|
||||||
|
return generics.txGenerics();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoundsList getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz) {
|
public BoundsList getBounds(RefTypeOrTPHOrWildcardOrGeneric type, ClassOrInterface clazz) {
|
||||||
|
Loading…
Reference in New Issue
Block a user