Merge branch 'targetBytecode' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into targetBytecode

This commit is contained in:
pl@gohorb.ba-horb.de 2022-08-08 11:50:07 +02:00
commit 975f2cefe3
14 changed files with 162 additions and 103 deletions

View File

@ -122,8 +122,8 @@ http://maven.apache.org/maven-v4_0_0.xsd">
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>18</source>
<target>18</target>
<source>17</source>
<target>17</target>
<compilerArgs>--enable-preview</compilerArgs>
</configuration>
</plugin>

View File

@ -2,10 +2,7 @@ package de.dhbwstuttgart.target.bytecode;
import de.dhbwstuttgart.target.tree.*;
import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.TargetFunNType;
import de.dhbwstuttgart.target.tree.type.TargetPrimitiveType;
import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetType;
import de.dhbwstuttgart.target.tree.type.*;
import org.objectweb.asm.*;
import java.lang.invoke.CallSite;
@ -13,10 +10,9 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.IntStream;
import static org.objectweb.asm.Opcodes.*;
import static de.dhbwstuttgart.target.tree.expression.TargetBinaryOp.*;
@ -26,6 +22,8 @@ public class Codegen {
private final TargetClass clazz;
private final ClassWriter cw;
public final String className;
private int lambdaCounter = 0;
private final HashMap<TargetLambdaExpression, TargetMethod> lambdas = new HashMap<>();
public Codegen(TargetClass clazz) {
this.clazz = clazz;
@ -62,7 +60,6 @@ public class Codegen {
private static class State {
Scope scope = new Scope(null);
int localCounter;
int lambdaCounter;
MethodVisitor mv;
State(MethodVisitor mv, int localCounter) {
@ -243,7 +240,7 @@ public class Codegen {
mv.visitInsn(I2D);
} else {
boxPrimitive(state, source);
mv.visitTypeInsn(CHECKCAST, dest.getName());
mv.visitTypeInsn(CHECKCAST, dest.getInternalName());
unboxPrimitive(state, dest);
}
}
@ -578,7 +575,7 @@ public class Codegen {
} else if (op.expr() instanceof TargetFieldVar fieldVar) {
generate(state, fieldVar.left());
mv.visitInsn(SWAP);
mv.visitFieldInsn(PUTFIELD, fieldVar.owner().getName(), fieldVar.right(), fieldVar.type().toSignature());
mv.visitFieldInsn(PUTFIELD, fieldVar.owner().getInternalName(), fieldVar.right(), fieldVar.type().toSignature());
}
}
@ -702,12 +699,19 @@ public class Codegen {
private void generateLambdaExpression(State state, TargetLambdaExpression lambda) {
var mv = state.mv;
var name = "lambda$" + state.lambdaCounter;
var impl = new TargetMethod(
0, name, Set.of(),
lambda.params(), lambda.returnType(), lambda.block()
);
generateMethod(impl);
TargetMethod impl;
if (lambdas.containsKey(lambda)) {
impl = lambdas.get(lambda);
} else {
var name = "lambda$" + lambdaCounter++;
impl = new TargetMethod(
0, name, Set.of(),
lambda.params(), lambda.returnType(), lambda.block()
);
generateMethod(impl);
lambdas.put(lambda, impl);
}
var mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class,
MethodType.class, MethodType.class, MethodHandle.class, MethodType.class);
@ -715,7 +719,7 @@ public class Codegen {
var bootstrap = new Handle(H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory", "metafactory",
mt.toMethodDescriptorString(), false);
var handle = new Handle(
H_INVOKEVIRTUAL, clazz.getName(), name,
H_INVOKEVIRTUAL, clazz.getName(), impl.name(),
impl.getDescriptor(), false
);
@ -731,8 +735,6 @@ public class Codegen {
mv.visitVarInsn(ALOAD, 0);
mv.visitInvokeDynamicInsn("apply", TargetMethod.getDescriptor(lambda.type(), new TargetRefType(clazz.qualifiedName())),
bootstrap, Type.getType(desugared), handle, Type.getType(impl.getDescriptor()));
state.lambdaCounter++;
}
private void generate(State state, TargetExpression expr) {
@ -760,7 +762,7 @@ public class Codegen {
convertTo(state, cast.expr().type(), cast.type());
break;
case TargetInstanceOf instanceOf:
mv.visitTypeInsn(INSTANCEOF, instanceOf.right().getName());
mv.visitTypeInsn(INSTANCEOF, instanceOf.right().getInternalName());
break;
case TargetLiteral literal:
switch (literal) {
@ -823,7 +825,7 @@ public class Codegen {
if (dot.isStatic())
mv.visitInsn(DUP);
else mv.visitInsn(DUP_X1);
mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.owner().getName(), dot.right(), dot.type().toSignature());
mv.visitFieldInsn(dot.isStatic() ? PUTSTATIC : PUTFIELD, dot.owner().getInternalName(), dot.right(), dot.type().toSignature());
break;
}
default:
@ -840,7 +842,7 @@ public class Codegen {
case TargetFieldVar dot: {
if (!dot.isStatic())
generate(state, dot.left());
mv.visitFieldInsn(dot.isStatic() ? GETSTATIC : GETFIELD, dot.left().type().getName(), dot.right(), dot.type().toSignature());
mv.visitFieldInsn(dot.isStatic() ? GETSTATIC : GETFIELD, dot.left().type().getInternalName(), dot.right(), dot.type().toSignature());
unboxPrimitive(state, dot.type());
break;
}
@ -926,11 +928,11 @@ public class Codegen {
);
mv.visitMethodInsn(call.isInterface() ? INVOKEINTERFACE : call.isStatic() ? INVOKESTATIC: call.name().equals("<init>") ? INVOKESPECIAL : INVOKEVIRTUAL,
call.owner().getName(), call.name(), descriptor, call.isInterface());
call.owner().getInternalName(), call.name(), descriptor, call.isInterface());
if (call.returnType() != null && !(call.returnType() instanceof TargetPrimitiveType)) {
if (!call.returnType().equals(call.type()))
mv.visitTypeInsn(CHECKCAST, call.type().getName());
if (!call.returnType().equals(call.type()) && !(call.type() instanceof TargetGenericType))
mv.visitTypeInsn(CHECKCAST, call.type().getInternalName());
else unboxPrimitive(state, call.type());
}
break;
@ -939,13 +941,13 @@ public class Codegen {
generateLambdaExpression(state, lambda);
break;
case TargetNew _new: {
mv.visitTypeInsn(NEW, _new.type().getName());
mv.visitTypeInsn(NEW, _new.type().getInternalName());
mv.visitInsn(DUP);
for (TargetExpression e : _new.params()) {
generate(state, e);
boxPrimitive(state, e.type());
}
mv.visitMethodInsn(INVOKESPECIAL, _new.type().getName(), "<init>", _new.getDescriptor(), false);
mv.visitMethodInsn(INVOKESPECIAL, _new.type().getInternalName(), "<init>", _new.getDescriptor(), false);
break;
}
default:
@ -963,7 +965,18 @@ public class Codegen {
var state = new State(mv, 1);
for (var param: constructor.parameters())
state.createVariable(param.name(), param.type());
generate(state, constructor.block());
var stmts = constructor.block().statements();
generate(state, stmts.get(0));
if (constructor.fieldInitializer() != null) {
var stmts2 = constructor.fieldInitializer().statements();
for (var i = 1; i < stmts2.size(); i++) {
generate(state, stmts2.get(i));
}
}
for (var i = 1; i < stmts.size(); i++)
generate(state, stmts.get(i));
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
@ -996,7 +1009,7 @@ public class Codegen {
public byte[] generate() {
cw.visit(V1_8, clazz.modifiers() | ACC_PUBLIC, clazz.qualifiedName(),
generateSignature(clazz), clazz.superType() != null ? clazz.superType().getName(): "java/lang/Object",
generateSignature(clazz), clazz.superType() != null ? clazz.superType().getInternalName(): "java/lang/Object",
clazz.implementingInterfaces().stream().map(TargetType::toSignature).toArray(String[]::new)
);
clazz.fields().forEach(this::generateField);

View File

@ -1,6 +1,7 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.bytecode.funN.FunNGenerator;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.parser.NullToken;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.factory.ASTFactory;
@ -174,9 +175,7 @@ public class ASTToTargetAST {
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) {
if (expressionReceiver.expr instanceof This) {
var optMethod = owner.getMethods().stream().filter(
m -> m.name.equals(methodCall.name) && parameterEquals(methodCall.getArgumentList(), methodCall.getArgumentList().getArguments())
).findFirst();
var optMethod = findMethod(owner, methodCall.name, methodCall.getArgumentList());
if (optMethod.isEmpty()) return;
var method = optMethod.get();
if (visitedMethods.contains(method)) return;
@ -451,19 +450,6 @@ public class ASTToTargetAST {
}
}
private boolean parameterEquals(ArgumentList argumentList, List<Expression> arguments) {
if (argumentList.getArguments().size() != arguments.size())
return false;
for (var i = 0; i < argumentList.getArguments().size(); i++) {
var type1 = convert(argumentList.getArguments().get(i).getType());
var type2 = convert(arguments.get(i).getType());
if (!type1.equals(type2)) return false;
}
return true;
}
protected ByteArrayClassLoader classLoader;
protected SourceFile sourceFile;
@ -571,6 +557,27 @@ public class ASTToTargetAST {
return cycles;
}
Optional<Method> findMethod(ClassOrInterface owner, String name, ArgumentList argumentList) {
return owner.getMethods().stream().filter(
m -> m.name.equals(name) && parameterEquals(m.getParameterList(), argumentList)
).findFirst();
}
boolean parameterEquals(ParameterList parameterList, ArgumentList argumentList) {
var pars = parameterList.getFormalparalist();
var arguments = argumentList.getArguments();
if (pars.size() != arguments.size())
return false;
for (var i = 0; i < pars.size(); i++) {
var type1 = convert(pars.get(i).getType());
var type2 = convert(arguments.get(i).getType());
if (!type1.equals(type2)) return false;
}
return true;
}
Set<TargetGeneric> convert(Set<ResultPair<?, ?>> result) {
return result.stream().map(p -> {
if (p instanceof PairTPHsmallerTPH pair) {
@ -584,12 +591,18 @@ public class ASTToTargetAST {
}
public TargetClass convert(ClassOrInterface input) {
currentClass = input;
TargetBlock fieldInitializer = null;
if (input.getfieldInitializations().isPresent())
fieldInitializer = convert(input.getfieldInitializations().get().block);
TargetBlock finalFieldInitializer = fieldInitializer;
return new TargetClass(input.getModifiers(), input.getClassName().toString(), convert(input.getSuperClass()),
convert(sigma.generics(input)),
input.getSuperInterfaces().stream().map(this::convert).toList(),
input.getConstructors().stream().map(constructor -> this.convert(input, constructor)).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.getMethods().stream().map(method -> this.convert(input, method)).flatMap(List::stream).toList()
input.getMethods().stream().map(this::convert).flatMap(List::stream).toList()
);
}
@ -598,18 +611,17 @@ public class ASTToTargetAST {
.map(param -> new MethodParameter(convert(param.getType()), param.getName())).toList();
}
private List<TargetConstructor> convert(ClassOrInterface owner, Constructor input) {
currentClass = owner;
private List<TargetConstructor> convert(Constructor input, TargetBlock fieldInitializer) {
sigma = all.get(0);
List<TargetConstructor> result = new ArrayList<>();
Set<List<MethodParameter>> parameterSet = new HashSet<>();
for (var s : all) {
sigma = s;
var generics = sigma.generics(owner, input);
var generics = sigma.generics(currentClass, input);
List<MethodParameter> params = convert(input.getParameterList());
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
result.add(new TargetConstructor(input.modifier, convert(generics), params, convert(input.block)));
result.add(new TargetConstructor(input.modifier, convert(generics), params, convert(input.block), fieldInitializer));
parameterSet.add(params);
}
}
@ -617,15 +629,14 @@ public class ASTToTargetAST {
return result;
}
private List<TargetMethod> convert(ClassOrInterface owner, Method input) {
currentClass = owner;
private List<TargetMethod> convert(Method input) {
sigma = all.get(0);
List<TargetMethod> result = new ArrayList<>();
Set<List<MethodParameter>> parameterSet = new HashSet<>();
for (var s : all) {
sigma = s;
var generics = sigma.generics(owner, input);
var generics = sigma.generics(currentClass, input);
List<MethodParameter> params = convert(input.getParameterList());
if (parameterSet.stream().noneMatch(p -> p.equals(params))) {
result.add(new TargetMethod(

View File

@ -3,7 +3,7 @@ package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.type.RefType;
@ -14,7 +14,10 @@ import de.dhbwstuttgart.target.tree.type.TargetRefType;
import de.dhbwstuttgart.target.tree.type.TargetSpecializedType;
import de.dhbwstuttgart.target.tree.type.TargetType;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@ -131,36 +134,60 @@ public class StatementToTargetExpression implements StatementVisitor {
result = new TargetVarDecl(converter.convert(localVarDecl.getType()), localVarDecl.getName(), null);
}
static boolean convertsTo(TargetType from, TargetType to) {
if (to.equals(TargetType.Object)) return true; // TODO Consider type coercion and suptyping
return to.equals(from);
}
Method findMethod(JavaClassName className, String name, List<TargetType> args) {
if (converter.sourceFile != null && converter.sourceFile.imports.contains(className)) {
try {
var clazz = converter.classLoader.loadClass(className.toString());
outer: for (var method : clazz.getMethods()) {
if (method.getParameterTypes().length != args.size()) continue;
if (!method.getName().equals(name)) continue;
for (var i = 0; i < method.getParameterTypes().length; i++) {
var param = method.getParameterTypes()[i];
var arg = args.get(i);
if (param.isPrimitive()) {
arg = TargetType.toPrimitive(arg);
}
if (!convertsTo(arg, Objects.requireNonNull(TargetType.toTargetType(param)))) continue outer;
}
return method;
}
} catch (ClassNotFoundException ignored) {}
}
if (converter.sourceFile != null) { // TODO Multiple source files
var thisClass = converter.sourceFile.KlassenVektor.stream()
.filter(classOrInterface -> classOrInterface.getClassName().equals(className)).findFirst();
if (thisClass.isPresent()) {
var superClass = thisClass.get().getSuperClass().getName();
return findMethod(superClass, name, args);
}
}
return null;
}
@Override
public void visit(MethodCall methodCall) {
var receiverType = converter.convert(methodCall.receiver.getType());
var isFunNType = receiverType instanceof TargetFunNType;
var returnType = converter.convert(methodCall.getType());
var receiverName = new JavaClassName(((TargetSpecializedType) converter.convert(methodCall.receiver.getType())).name());
var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.getType());
var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name());
var argList = methodCall.arglist.getArguments().stream().map(expr -> converter.convert(expr.getType())).toList();
java.lang.reflect.Method foundMethod = null;
if (converter.sourceFile != null && converter.sourceFile.imports.contains(receiverName)) {
try {
var clazz = converter.classLoader.loadClass(receiverName.toString());
outer: for (var method : clazz.getMethods()) {
if (method.getParameterTypes().length != argList.size()) continue;
if (!method.getName().equals(methodCall.name)) continue;
for (var i = 0; i < method.getParameterTypes().length; i++) {
var param = method.getParameterTypes()[i];
var arg = argList.get(i);
if (param.isPrimitive()) {
arg = TargetType.toPrimitive(arg);
}
if (!TargetType.toTargetType(param).equals(arg)) continue outer;
}
foundMethod = method;
break;
}
} catch (ClassNotFoundException ignored) {}
Method foundMethod = null;
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver && expressionReceiver.expr instanceof This) {
var thisMethod = converter.findMethod(converter.currentClass, methodCall.name, methodCall.arglist);
if (thisMethod.isEmpty()) {
foundMethod = findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, argList);
}
} else {
foundMethod = findMethod(receiverName, methodCall.name, argList);
}
if (foundMethod != null) {

View File

@ -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) {
this.constructors.add(new TargetConstructor(access, generics, paramterTypes, block));
this.constructors.add(new TargetConstructor(access, generics, paramterTypes, block, null));
}
public void addConstructor(int access, List<MethodParameter> paramterTypes, TargetBlock block) {

View File

@ -6,7 +6,7 @@ import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.List;
import java.util.Set;
public record TargetConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetBlock block) {
public record TargetConstructor(int access, Set<TargetGeneric> generics, List<MethodParameter> parameters, TargetBlock block, TargetBlock fieldInitializer) {
public String getDescriptor() {
return TargetMethod.getDescriptor(null, parameters.stream().map(MethodParameter::type).toArray(TargetType[]::new));

View File

@ -12,8 +12,13 @@ public record TargetExtendsWildcard(TargetType innerType) implements TargetType
}
@Override
public String getName() {
return innerType.getName();
public String getInternalName() {
return innerType.getInternalName();
}
@Override
public String name() {
return innerType.name();
}
}

View File

@ -4,17 +4,17 @@ import java.util.List;
public record TargetFunNType(int N, List<TargetType> params) implements TargetSpecializedType {
@Override
public String getName() {
public String getInternalName() {
return "Fun" + N + "$$";
}
@Override
public String name() {
return getName();
return getInternalName();
}
@Override
public String toSignature() {
return "L" + getName() + ";";
return "L" + getInternalName() + ";";
}
}

View File

@ -8,11 +8,11 @@ public record TargetGenericType(String name) implements TargetType {
@Override
public String toGenericSignature() {
return "T" + getName() + ";";
return "T" + getInternalName() + ";";
}
@Override
public String getName() {
public String getInternalName() {
return name;
}
}

View File

@ -4,7 +4,7 @@ public record TargetPrimitiveType(String name) implements TargetType {
@Override
public String toSignature() {
return getName();
return getInternalName();
}
@Override
@ -13,7 +13,7 @@ public record TargetPrimitiveType(String name) implements TargetType {
}
@Override
public String getName() {
public String getInternalName() {
return name;
}
}

View File

@ -1,7 +1,5 @@
package de.dhbwstuttgart.target.tree.type;
import de.dhbwstuttgart.target.tree.type.TargetType;
import java.util.List;
import java.util.Objects;
@ -10,13 +8,13 @@ public record TargetRefType(String name, List<TargetType> params) implements Tar
this(name, List.of());
}
public String getName() {
public String getInternalName() {
return this.name.replaceAll("\\.", "/");
}
@Override
public String toSignature() {
return "L" + getName() + ";";
return "L" + getInternalName() + ";";
}
// Type erasure means we need to override hashCode and equals to only consider the name

View File

@ -7,7 +7,7 @@ public sealed interface TargetSpecializedType extends TargetType permits TargetF
@Override
default String toGenericSignature() {
String ret = "L" + getName();
String ret = "L" + getInternalName();
if (params().size() > 0) {
ret += "<";
for (var param : params()) {
@ -18,6 +18,4 @@ public sealed interface TargetSpecializedType extends TargetType permits TargetF
ret += ";";
return ret;
}
String name();
}

View File

@ -12,7 +12,14 @@ public record TargetSuperWildcard(TargetType innerType) implements TargetType {
}
@Override
public String getName() {
return innerType.getName();
public String getInternalName() {
return innerType.getInternalName();
}
@Override
public String name() {
return innerType.name();
}
}

View File

@ -1,7 +1,5 @@
package de.dhbwstuttgart.target.tree.type;
import java.util.List;
public sealed interface TargetType
permits TargetExtendsWildcard, TargetGenericType, TargetSpecializedType, TargetSuperWildcard, TargetPrimitiveType {
@ -50,10 +48,12 @@ public sealed interface TargetType
if (clazz.equals(float.class)) return float_;
if (clazz.equals(double.class)) return double_;
}
if (clazz.equals(void.class)) return null;
return new TargetRefType(clazz.getName());
}
String toSignature();
String toGenericSignature();
String getName();
String getInternalName();
String name();
}