forked from JavaTX/JavaCompilerCore
Generate attribute for JavaTX
This commit is contained in:
parent
68034ed434
commit
374d2e811b
@ -708,7 +708,7 @@ public class Codegen {
|
|||||||
parameters.addAll(lambda.params());
|
parameters.addAll(lambda.params());
|
||||||
|
|
||||||
impl = new TargetMethod(
|
impl = new TargetMethod(
|
||||||
0, name, Set.of(),
|
0, name, Set.of(), Set.of(),
|
||||||
parameters, lambda.returnType(), lambda.block()
|
parameters, lambda.returnType(), lambda.block()
|
||||||
);
|
);
|
||||||
generateMethod(impl);
|
generateMethod(impl);
|
||||||
@ -980,6 +980,9 @@ public class Codegen {
|
|||||||
|
|
||||||
private void generateConstructor(TargetConstructor constructor) {
|
private void generateConstructor(TargetConstructor constructor) {
|
||||||
MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "<init>", constructor.getDescriptor(), constructor.getSignature(), null);
|
MethodVisitor mv = cw.visitMethod(constructor.access() | ACC_PUBLIC, "<init>", constructor.getDescriptor(), constructor.getSignature(), null);
|
||||||
|
if (!constructor.txGenerics().isEmpty())
|
||||||
|
mv.visitAttribute(new JavaTXSignatureAttribute(constructor.getTXSignature()));
|
||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
var state = new State(null, mv, 1);
|
var state = new State(null, mv, 1);
|
||||||
for (var param: constructor.parameters())
|
for (var param: constructor.parameters())
|
||||||
@ -1004,6 +1007,9 @@ public class Codegen {
|
|||||||
private void generateMethod(TargetMethod method) {
|
private void generateMethod(TargetMethod method) {
|
||||||
// TODO The older codegen has set ACC_PUBLIC for all methods, good for testing but bad for everything else
|
// 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);
|
MethodVisitor mv = cw.visitMethod(method.access() | ACC_PUBLIC, method.name(), method.getDescriptor(), method.getSignature(), null);
|
||||||
|
if (!method.txGenerics().isEmpty())
|
||||||
|
mv.visitAttribute(new JavaTXSignatureAttribute(method.getTXSignature()));
|
||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
var state = new State(method.returnType(), mv, method.isStatic() ? 0 : 1);
|
var state = new State(method.returnType(), mv, method.isStatic() ? 0 : 1);
|
||||||
for (var param: method.parameters())
|
for (var param: method.parameters())
|
||||||
@ -1015,9 +1021,9 @@ public class Codegen {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generateSignature(TargetClass clazz) {
|
private static String generateSignature(TargetClass clazz, Set<TargetGeneric> generics) {
|
||||||
String ret = "<";
|
String ret = "<";
|
||||||
for (var generic : clazz.generics()) {
|
for (var generic : generics) {
|
||||||
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
ret += generic.name() + ":" + generic.bound().toDescriptor();
|
||||||
}
|
}
|
||||||
ret += ">";
|
ret += ">";
|
||||||
@ -1028,9 +1034,12 @@ public class Codegen {
|
|||||||
|
|
||||||
public byte[] generate() {
|
public byte[] generate() {
|
||||||
cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC | ACC_SUPER, clazz.qualifiedName(),
|
cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC | ACC_SUPER, clazz.qualifiedName(),
|
||||||
generateSignature(clazz), clazz.superType() != null ? clazz.superType().getInternalName(): "java/lang/Object",
|
generateSignature(clazz, clazz.generics()), clazz.superType() != null ? clazz.superType().getInternalName(): "java/lang/Object",
|
||||||
clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)
|
clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)
|
||||||
);
|
);
|
||||||
|
if (!clazz.txGenerics().isEmpty())
|
||||||
|
cw.visitAttribute(new JavaTXSignatureAttribute(generateSignature(clazz, clazz.txGenerics())));
|
||||||
|
|
||||||
clazz.fields().forEach(this::generateField);
|
clazz.fields().forEach(this::generateField);
|
||||||
clazz.constructors().forEach(this::generateConstructor);
|
clazz.constructors().forEach(this::generateConstructor);
|
||||||
clazz.methods().forEach(this::generateMethod);
|
clazz.methods().forEach(this::generateMethod);
|
||||||
|
@ -2,6 +2,9 @@ package de.dhbwstuttgart.bytecode;
|
|||||||
|
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class JavaTXSignatureAttribute extends Attribute {
|
public class JavaTXSignatureAttribute extends Attribute {
|
||||||
final String signature;
|
final String signature;
|
||||||
|
|
||||||
@ -12,7 +15,9 @@ public class JavaTXSignatureAttribute extends Attribute {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) {
|
protected Attribute read(ClassReader classReader, int offset, int length, char[] charBuffer, int codeAttributeOffset, Label[] labels) {
|
||||||
return super.read(classReader, offset, length, charBuffer, codeAttributeOffset, labels);
|
var data = new byte[length];
|
||||||
|
System.arraycopy(classReader.b, offset, data, 0, length);
|
||||||
|
return new JavaTXSignatureAttribute(new String(data, StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -501,26 +501,42 @@ public class ASTToTargetAST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
javaResult.addAll(txResult); // Same result until here
|
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
|
var eq = new HashMap<>(equality);
|
||||||
// TODO Maybe don't do this twice?
|
{ // Java Generics
|
||||||
var usedTphs = new HashSet<TypePlaceholder>();
|
eliminateCycles(javaResult);
|
||||||
for (var param : method.getParameterList().getFormalparalist()) {
|
eliminateInfima(javaResult);
|
||||||
usedTphs.addAll(findTypeVariables(param.getType()));
|
|
||||||
|
var usedTphs = new HashSet<TypePlaceholder>();
|
||||||
|
// For eliminating inner type variables we need to figure out which ones are actually used
|
||||||
|
// TODO Maybe don't do this twice?
|
||||||
|
for (var param : method.getParameterList().getFormalparalist()) {
|
||||||
|
usedTphs.addAll(findTypeVariables(param.getType()));
|
||||||
|
}
|
||||||
|
usedTphs.addAll(findTypeVariables(method.getReturnType()));
|
||||||
|
var referenced = new HashSet<>(usedTphs);
|
||||||
|
referenced.addAll(typeVariablesOfClass);
|
||||||
|
|
||||||
|
eliminateInnerTypeVariables(referenced, javaResult);
|
||||||
|
equalizeTypeVariables(javaResult);
|
||||||
|
usedTPHsOfMethods.put(method, usedTphs);
|
||||||
}
|
}
|
||||||
usedTphs.addAll(findTypeVariables(method.getReturnType()));
|
|
||||||
var referenced = new HashSet<>(usedTphs);
|
|
||||||
referenced.addAll(typeVariablesOfClass);
|
|
||||||
|
|
||||||
eliminateInnerTypeVariables(referenced, javaResult);
|
var storedEq = equality; //TODO Hack: pass equality as parameter instead
|
||||||
eliminateInnerTypeVariables(referenced, txResult);
|
equality = eq;
|
||||||
|
{ // JavaTX Generics
|
||||||
|
eliminateInfima(txResult);
|
||||||
|
|
||||||
usedTPHsOfMethods.put(method, usedTphs);
|
var referenced = new HashSet<TypePlaceholder>();
|
||||||
|
for (var param : method.getParameterList().getFormalparalist()) {
|
||||||
|
referenced.addAll(findTypeVariables(param.getType()));
|
||||||
|
}
|
||||||
|
referenced.addAll(findTypeVariables(method.getReturnType()));
|
||||||
|
referenced.addAll(typeVariablesOfClass);
|
||||||
|
|
||||||
equalizeTypeVariables(javaResult);
|
eliminateInnerTypeVariables(referenced, txResult);
|
||||||
|
}
|
||||||
|
equality = storedEq;
|
||||||
|
|
||||||
System.out.println(method.name + ": " + txResult + " & " + javaResult);
|
System.out.println(method.name + ": " + txResult + " & " + javaResult);
|
||||||
|
|
||||||
@ -898,18 +914,21 @@ public class ASTToTargetAST {
|
|||||||
|
|
||||||
public TargetClass convert(ClassOrInterface input) {
|
public TargetClass convert(ClassOrInterface input) {
|
||||||
currentClass = input;
|
currentClass = input;
|
||||||
Set<TargetGeneric> generics = new HashSet<>();
|
Set<TargetGeneric> javaGenerics = new HashSet<>();
|
||||||
|
Set<TargetGeneric> txGenerics = new HashSet<>();
|
||||||
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 Generics(new HashSet<>(), 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));
|
javaGenerics.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).javaGenerics());
|
var generics = sigma.generics(input);
|
||||||
|
javaGenerics = convert(generics.javaGenerics());
|
||||||
|
txGenerics = convert(generics.txGenerics());
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetBlock fieldInitializer = null;
|
TargetBlock fieldInitializer = null;
|
||||||
@ -918,7 +937,7 @@ public class ASTToTargetAST {
|
|||||||
TargetBlock finalFieldInitializer = fieldInitializer;
|
TargetBlock finalFieldInitializer = fieldInitializer;
|
||||||
|
|
||||||
return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass()),
|
return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass()),
|
||||||
generics,
|
javaGenerics, txGenerics,
|
||||||
input.getSuperInterfaces().stream().map(this::convert).toList(),
|
input.getSuperInterfaces().stream().map(this::convert).toList(),
|
||||||
input.getConstructors().stream().map(constructor -> this.convert(constructor, finalFieldInitializer)).flatMap(List::stream).toList(),
|
input.getConstructors().stream().map(constructor -> this.convert(constructor, finalFieldInitializer)).flatMap(List::stream).toList(),
|
||||||
input.getFieldDecl().stream().map(this::convert).toList(),
|
input.getFieldDecl().stream().map(this::convert).toList(),
|
||||||
@ -970,8 +989,10 @@ 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.javaGenerics(), input);
|
var javaGenerics = collectMethodGenerics(generics.javaGenerics(), input);
|
||||||
result.add(new TargetConstructor(input.modifier, convertedGenerics, params, convert(input.block), fieldInitializer));
|
var txGenerics = collectMethodGenerics(generics.txGenerics(), input);
|
||||||
|
|
||||||
|
result.add(new TargetConstructor(input.modifier, javaGenerics, txGenerics, params, convert(input.block), fieldInitializer));
|
||||||
parameterSet.add(params);
|
parameterSet.add(params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -989,10 +1010,12 @@ 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.javaGenerics(), input);
|
var javaGenerics = collectMethodGenerics(generics.javaGenerics(), input);
|
||||||
|
var txGenerics = collectMethodGenerics(generics.txGenerics(), input);
|
||||||
|
|
||||||
result.add(new TargetMethod(
|
result.add(new TargetMethod(
|
||||||
input.modifier,
|
input.modifier,
|
||||||
input.name, convertedGenerics, params,
|
input.name, javaGenerics, txGenerics, params,
|
||||||
convert(input.getReturnType()),
|
convert(input.getReturnType()),
|
||||||
convert(input.block)
|
convert(input.block)
|
||||||
));
|
));
|
||||||
|
@ -10,14 +10,14 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set<TargetGeneric> generics, List<TargetType> implementingInterfaces,
|
public record TargetClass(int modifiers, String qualifiedName, TargetType superType, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<TargetType> implementingInterfaces,
|
||||||
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) {
|
List<TargetConstructor> constructors, List<TargetField> fields, List<TargetMethod> methods) {
|
||||||
|
|
||||||
public TargetClass(int modifiers, String qualifiedName) {
|
public TargetClass(int modifiers, String qualifiedName) {
|
||||||
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||||
}
|
}
|
||||||
public TargetClass(int modifiers, String qualifiedName, List<TargetType> implementingInterfaces) {
|
public TargetClass(int modifiers, String qualifiedName, List<TargetType> implementingInterfaces) {
|
||||||
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
this(modifiers, qualifiedName, TargetType.Object, new HashSet<>(), new HashSet<>(), implementingInterfaces, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -25,7 +25,7 @@ public record TargetClass(int modifiers, String qualifiedName, TargetType superT
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
public void addMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
||||||
this.methods.add(new TargetMethod(access, name, generics, parameterTypes, returnType, block));
|
this.methods.add(new TargetMethod(access, name, generics, Set.of(), parameterTypes, returnType, block));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMethod(int access, String name, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
public void addMethod(int access, String name, List<MethodParameter> parameterTypes, TargetType returnType, TargetBlock block) {
|
||||||
@ -33,7 +33,7 @@ public record TargetClass(int modifiers, String qualifiedName, TargetType superT
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> paramterTypes, TargetBlock block) {
|
public void addConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||||
this.constructors.add(new TargetConstructor(access, generics, paramterTypes, block, null));
|
this.constructors.add(new TargetConstructor(access, generics, Set.of(), paramterTypes, block, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {
|
public void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {
|
||||||
|
@ -6,7 +6,7 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public record TargetConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetBlock block, TargetBlock fieldInitializer) {
|
public record TargetConstructor(int access, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<MethodParameter> parameters, TargetBlock block, TargetBlock fieldInitializer) {
|
||||||
|
|
||||||
public String getDescriptor() {
|
public String getDescriptor() {
|
||||||
return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));
|
return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));
|
||||||
@ -15,5 +15,9 @@ public record TargetConstructor(int access, Set<TargetGeneric> generics, List<Me
|
|||||||
public String getSignature() {
|
public String getSignature() {
|
||||||
return TargetMethod.getSignature(generics, parameters, null);
|
return TargetMethod.getSignature(generics, parameters, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTXSignature() {
|
||||||
|
return TargetMethod.getSignature(txGenerics, parameters, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import org.objectweb.asm.Opcodes;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public record TargetMethod(int access, String name, Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetType returnType, TargetBlock block) {
|
public record TargetMethod(int access, String name, Set<TargetGeneric> generics, Set<TargetGeneric> txGenerics, List<MethodParameter> parameters, TargetType returnType, TargetBlock block) {
|
||||||
public static String getDescriptor(TargetType returnType, TargetType... parameters) {
|
public static String getDescriptor(TargetType returnType, TargetType... parameters) {
|
||||||
String ret = "(";
|
String ret = "(";
|
||||||
for (var parameterType : parameters) {
|
for (var parameterType : parameters) {
|
||||||
@ -42,6 +42,10 @@ public record TargetMethod(int access, String name, Set<TargetGeneric> generics,
|
|||||||
return getSignature(generics, parameters, returnType);
|
return getSignature(generics, parameters, returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTXSignature() {
|
||||||
|
return getSignature(txGenerics, parameters, returnType);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isStatic() {
|
public boolean isStatic() {
|
||||||
return (access & Opcodes.ACC_STATIC) != 0;
|
return (access & Opcodes.ACC_STATIC) != 0;
|
||||||
}
|
}
|
||||||
|
@ -579,4 +579,10 @@ public class TestComplete {
|
|||||||
var classFiles = generateClassFiles("Box.jav", new ByteArrayClassLoader());
|
var classFiles = generateClassFiles("Box.jav", new ByteArrayClassLoader());
|
||||||
var instance = classFiles.get("Box_Main").getDeclaredConstructor().newInstance();
|
var instance = classFiles.get("Box_Main").getDeclaredConstructor().newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cycleTest() throws Exception {
|
||||||
|
var classFiles = generateClassFiles("Cycle.jav", new ByteArrayClassLoader());
|
||||||
|
var instance = classFiles.get("Cycle").getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user