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 2023-11-03 18:42:09 +01:00
commit fba7f0ee81
13 changed files with 144 additions and 81 deletions

View File

@ -1,14 +1,17 @@
import java.lang.Runnable;
import java.lang.String;
import java.lang.System;
import java.io.PrintStream;
public class LamRunnable{
public class LambdaRunnable {
public LamRunnable(){
public LambdaRunnable(){
Runnable lam;
lam = () -> {var a;};
//lam.run();
Runnable lam = () -> {
System.out.println("Runnable is running");
};
lam.run();
}
}

View File

@ -76,6 +76,8 @@ public class Codegen {
int localCounter;
MethodVisitor mv;
TargetType returnType;
// This is used to remember the type from lambda expressions
TargetType contextType;
Stack<BreakEnv> breakStack = new Stack<>();
Stack<Integer> switchResultValue = new Stack<>();
@ -747,14 +749,19 @@ public class Codegen {
params.add(new TargetRefType(clazz.qualifiedName().getClassName()));
params.addAll(lambda.captures().stream().map(mp -> mp.pattern().type()).toList());
var descriptor = TargetMethod.getDescriptor(lambda.type(), params.toArray(TargetType[]::new));
var descriptor = TargetMethod.getDescriptor(state.contextType, params.toArray(TargetType[]::new));
mv.visitVarInsn(ALOAD, 0);
for (var capture : lambda.captures()) {
var pattern = (TargetTypePattern) capture.pattern();
mv.visitVarInsn(ALOAD, state.scope.get(pattern.name()).index);
}
mv.visitInvokeDynamicInsn("apply", descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new))));
String methodName;
var intf = compiler.getClass(new JavaClassName(state.contextType.name()));
if (intf == null) methodName = "apply"; // TODO Weird fallback logic here
else methodName = intf.getMethods().stream().filter(m -> Modifier.isAbstract(m.modifier)).findFirst().orElseThrow().getName();
mv.visitInvokeDynamicInsn(methodName, descriptor, bootstrap, Type.getType(desugared), handle, Type.getType(TargetMethod.getDescriptor(impl.signature().returnType(), lambda.params().stream().map(mp -> mp.pattern().type()).toArray(TargetType[]::new))));
}
private void generate(State state, TargetExpression expr) {
@ -781,7 +788,10 @@ public class Codegen {
break;
}
case TargetCast cast:
var ctx = state.contextType;
state.contextType = cast.type();
generate(state, cast.expr());
state.contextType = ctx;
convertTo(state, cast.expr().type(), cast.type());
break;
case TargetInstanceOf instanceOf:
@ -825,7 +835,11 @@ public class Codegen {
case TargetAssign assign: {
switch (assign.left()) {
case TargetLocalVar localVar -> {
var ctype = state.contextType;
state.contextType = localVar.type();
generate(state, assign.right());
state.contextType = ctype;
convertTo(state, assign.right().type(), localVar.type());
boxPrimitive(state, localVar.type());
var local = state.scope.get(localVar.name());
@ -836,7 +850,12 @@ public class Codegen {
var fieldType = dot.type();
if (!(dot.left() instanceof TargetThis && dot.isStatic()))
generate(state, dot.left());
var ctype = state.contextType;
state.contextType = fieldType;
generate(state, assign.right());
state.contextType = ctype;
convertTo(state, assign.right().type(), fieldType);
boxPrimitive(state, fieldType);
if (dot.isStatic())
@ -934,7 +953,10 @@ public class Codegen {
}
case TargetReturn ret: {
if (ret.expression() != null && state.returnType != null) {
var ctype = state.contextType;
state.contextType = state.returnType;
generate(state, ret.expression());
state.contextType = ctype;
convertTo(state, ret.expression().type(), state.returnType);
boxPrimitive(state, state.returnType);
mv.visitInsn(ARETURN);
@ -981,9 +1003,12 @@ public class Codegen {
for (var i = 0; i < call.args().size(); i++) {
var e = call.args().get(i);
var arg = call.parameterTypes().get(i);
var ctype = state.contextType;
state.contextType = arg;
generate(state, e);
if (!(arg instanceof TargetPrimitiveType))
boxPrimitive(state, e.type());
state.contextType = ctype;
}
var descriptor = call.getDescriptor();
if (call.owner() instanceof TargetFunNType) // Decay FunN

View File

@ -28,12 +28,15 @@ public class FunNGenerator {
private static final String objectSuperType = Type.getInternalName(Object.class).replace('.','/');
private static final String objectSignature = applySignature(TargetType.Object);
private static final String VOID = "Ljava/lang/Void;";
public static class GenericParameters {
int start;
public List<TargetType> parameters = new ArrayList<>();
}
private static String applyDescriptor(TargetType type, GenericParameters gep) {
if (type == null) return VOID;
var res = "L" + type.getInternalName();
if (type instanceof TargetSpecializedType a) {
if (a.params().size() > 0) {
@ -62,6 +65,7 @@ public class FunNGenerator {
private static String applyNameDescriptor(TargetType a){ return a instanceof TargetGenericType ? "LTPH;" : String.format("%s", applySignature(a)); }
public static String encodeType(TargetType type) {
if (type == null) return VOID;
return applyNameDescriptor(type).replace("/", "$").replace(";", "$_$");
}

View File

@ -121,7 +121,8 @@ public class JavaTXCompiler {
}
try {
var clazz = classLoader.loadClass(name.toString());
return ASTFactory.createClass(clazz);
if (clazz != null)
return ASTFactory.createClass(clazz);
} catch (ClassNotFoundException ignored) {}
return null;
}
@ -418,7 +419,9 @@ public class JavaTXCompiler {
final ConstraintSet<Pair> cons = getConstraints();
Set<Set<UnifyPair>> results = new HashSet<>();
try {
Writer logFile = log ? new FileWriter(new File(System.getProperty("user.dir") + "/logFiles/" + "log_" + sourceFiles.keySet().iterator().next().getName())) : new OutputStreamWriter(new NullOutputStream());
var logFolder = new File(System.getProperty("user.dir") + "/logFiles/");
if (log) logFolder.mkdirs();
Writer logFile = log ? new FileWriter(new File(logFolder, "log_" + sourceFiles.keySet().iterator().next().getName())) : new OutputStreamWriter(new NullOutputStream());
IFiniteClosure finiteClosure = UnifyTypeFactory.generateFC(allClasses, logFile, classLoader);
System.out.println(finiteClosure);
ConstraintSet<UnifyPair> unifyCons = UnifyTypeFactory.convert(cons);
@ -742,7 +745,7 @@ public class JavaTXCompiler {
}
public synchronized Map<JavaClassName, byte[]> generateBytecode(SourceFile sf, List<ResultSet> typeInferenceResult) {
var converter = new ASTToTargetAST(typeInferenceResult, sf, classLoader);
var converter = new ASTToTargetAST(this, typeInferenceResult, sf, classLoader);
var generatedClasses = new HashMap<JavaClassName, byte[]>();
for (var clazz : sf.getClasses()) {
var codegen = new Codegen(converter.convert(clazz), this);

View File

@ -1,5 +1,6 @@
package de.dhbwstuttgart.syntaxtree.factory;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
@ -45,7 +46,7 @@ public class ASTFactory {
try {
var path = jreClass.getName().replace('.', '/') + ".class";
var classLoader = jreClass.getClassLoader();
if (classLoader != null) {
if (classLoader != null && new File(path).exists()) {
var bytes = IOUtils.toByteArray(Objects.requireNonNull(classLoader.getResourceAsStream(path)));
var classReader = new ClassReader(bytes);
var classVisitor = new ClassVisitor(Opcodes.ASM7) {
@ -354,19 +355,19 @@ public class ASTFactory {
if (type == null || type.getTypeName().equals("void")) {
return new Void(new NullToken());
} else if (type.getTypeName().equals("int")) {
return new RefType(new JavaClassName("java.lang.Integer"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Integer"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("byte")) {
return new RefType(new JavaClassName("java.lang.Byte"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Byte"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("boolean")) {
return new RefType(new JavaClassName("java.lang.Boolean"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Boolean"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("char")) {
return new RefType(new JavaClassName("java.lang.Char"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Char"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("short")) {
return new RefType(new JavaClassName("java.lang.Short"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Short"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("double")) {
return new RefType(new JavaClassName("java.lang.Double"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Double"), new ArrayList<>(), new NullToken(), true);
} else if (type.getTypeName().equals("long")) {
return new RefType(new JavaClassName("java.lang.Long"), new ArrayList<>(), new NullToken());
return new RefType(new JavaClassName("java.lang.Long"), new ArrayList<>(), new NullToken(), true);
} else {
if (type instanceof TypeVariable) {
// GTVDeclarationContext via "(TypeVariable) type).getGenericDeclaration()"

View File

@ -38,7 +38,11 @@ public class MethodCall extends Statement
this.receiverType = receiverType;
this.signature = signature;
}
public List<RefTypeOrTPHOrWildcardOrGeneric> signatureArguments() {
return signature.subList(0, signature.size() - 1);
}
@Override
public void accept(StatementVisitor visitor) {

View File

@ -8,6 +8,7 @@ public class ThisCall extends MethodCall
{
public ThisCall(Receiver receiver, ArgumentList arglist, int offset)
{
// TODO What is this?
super(null, null, null, null, null, null, null);
}

View File

@ -20,13 +20,17 @@ public class RefType extends RefTypeOrTPHOrWildcardOrGeneric
*
* Bsp: java.lang.Integer mit Flag wird dann zu [int]
*/
private boolean primitiveFlag=false;
boolean primitiveFlag = false; // TODO Should be final
public RefType(JavaClassName fullyQualifiedName, Token offset)
{
this(fullyQualifiedName, new ArrayList<>(), offset);
}
public boolean isPrimitive() {
return primitiveFlag;
}
@Override
public String toString(){
String params = "";
@ -51,11 +55,15 @@ public class RefType extends RefTypeOrTPHOrWildcardOrGeneric
return hash;
}
public RefType(JavaClassName fullyQualifiedName, List<RefTypeOrTPHOrWildcardOrGeneric> parameter, Token offset)
{
public RefType(JavaClassName fullyQualifiedName, List<RefTypeOrTPHOrWildcardOrGeneric> parameter, Token offset) {
this(fullyQualifiedName, parameter, offset, false);
}
public RefType(JavaClassName fullyQualifiedName, List<RefTypeOrTPHOrWildcardOrGeneric> parameter, Token offset, boolean primitiveFlag) {
super(offset);
this.name = (fullyQualifiedName);
this.parameter = parameter;
this.primitiveFlag = primitiveFlag;
}
public JavaClassName getName()

View File

@ -1,6 +1,7 @@
package de.dhbwstuttgart.target.generate;
import de.dhbwstuttgart.bytecode.FunNGenerator;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.environment.ByteArrayClassLoader;
import de.dhbwstuttgart.environment.IByteArrayClassLoader;
import de.dhbwstuttgart.exceptions.NotImplementedException;
@ -15,6 +16,7 @@ import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*;
import de.dhbwstuttgart.typeinference.result.*;
import javax.sql.rowset.RowSetWarning;
import java.lang.annotation.Target;
import java.util.*;
import java.util.stream.Collectors;
@ -31,6 +33,8 @@ public class ASTToTargetAST {
protected Generics generics;
final Map<ClassOrInterface, Set<GenericTypeVar>> userDefinedGenerics = new HashMap<>();
public final JavaTXCompiler compiler;
protected ClassOrInterface currentClass; // TODO This is only needed because of SuperCall, maybe there's
public List<GenericsResult> txGenerics() {
@ -55,10 +59,14 @@ public class ASTToTargetAST {
protected SourceFile sourceFile;
public ASTToTargetAST(List<ResultSet> resultSets) {
this(resultSets, null, new ByteArrayClassLoader());
this(null, resultSets);
}
public ASTToTargetAST(JavaTXCompiler compiler, List<ResultSet> resultSets) {
this(compiler, resultSets, null, new ByteArrayClassLoader());
}
public ASTToTargetAST(List<ResultSet> resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) {
public ASTToTargetAST(JavaTXCompiler compiler, List<ResultSet> resultSets, SourceFile sourceFile, IByteArrayClassLoader classLoader) {
this.compiler = compiler;
this.classLoader = classLoader;
this.sourceFile = sourceFile;
@ -69,20 +77,26 @@ public class ASTToTargetAST {
this.generics = all.get(0);
}
Optional<Method> findMethod(ClassOrInterface owner, String name, ArgumentList argumentList) {
return owner.getMethods().stream().filter(m -> m.name.equals(name) && parameterEquals(m.getParameterList(), argumentList)).findFirst();
Optional<Method> findMethod(ClassOrInterface owner, String name, List<TargetType> argumentList) {
Optional<Method> method = Optional.empty();
while (method.isEmpty() && !owner.getClassName().toString().equals("java.lang.Object")) {
method = owner.getMethods().stream().filter(m -> m.name.equals(name) && parameterEquals(m.getParameterList(), argumentList)).findFirst();
owner = compiler.getClass(owner.getSuperClass().getName());
}
return method;
}
boolean parameterEquals(ParameterList parameterList, ArgumentList argumentList) {
boolean parameterEquals(ParameterList parameterList, List<TargetType> arguments) {
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(), generics.javaGenerics);
var type2 = convert(arguments.get(i).getType(), generics.javaGenerics);
if (type2 instanceof TargetGenericType && type1 instanceof TargetGenericType)
var type2 = arguments.get(i);
if (type1 instanceof TargetGenericType)
return true;
if (TargetType.toPrimitive(type2).equals(type1))
return true;
if (!type1.equals(type2))
return false;
@ -398,8 +412,7 @@ public class ASTToTargetAST {
static TargetType flattenFunNType(List<TargetType> params, FunNGenerator.GenericParameters gep) {
var newParams = new ArrayList<TargetType>();
for (var i = 0; i < params.size(); i++) {
var param = params.get(i);
for (TargetType param : params) {
if (param instanceof TargetSpecializedType fn) {
collectArguments(fn, newParams);
} else {
@ -421,8 +434,16 @@ public class ASTToTargetAST {
var name = refType.getName().toString();
if (name.equals("void"))
return null;
if (refType.isPrimitive()) {
return TargetType.toPrimitive(refType);
}
var params = refType.getParaList().stream().map(type -> {
var res = convert(type, generics);
if (res == null) res = new TargetRefType("java.lang.Void");
return res;
}).toList();
var params = refType.getParaList().stream().map(type -> convert(type, generics)).toList();
if (name.matches("Fun\\d+\\$\\$")) { // TODO This seems like a bad idea
var className = FunNGenerator.getSpecializedClassName(FunNGenerator.getArguments(params), FunNGenerator.getReturnType(params));
if (!usedFunNSuperTypes.contains(params.size())) {

View File

@ -297,7 +297,7 @@ public abstract class GenerateGenerics {
if (methodCall.receiver instanceof ExpressionReceiver expressionReceiver) {
if (expressionReceiver.expr instanceof This) {
var optMethod = astToTargetAST.findMethod(owner, methodCall.name, methodCall.getArgumentList());
var optMethod = astToTargetAST.findMethod(owner, methodCall.name, methodCall.signatureArguments().stream().map(astToTargetAST::convert).toList());
if (optMethod.isEmpty()) return;
var method2 = optMethod.get();
System.out.println("In: " + method.getName() + " Method: " + method2.getName());

View File

@ -4,13 +4,15 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.factory.PrimitiveMethodsGenerator;
import de.dhbwstuttgart.syntaxtree.statement.*;
import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.target.tree.MethodParameter;
import de.dhbwstuttgart.target.tree.expression.*;
import de.dhbwstuttgart.target.tree.type.*;
import java.lang.reflect.Method;
import javax.swing.text.html.Option;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@ -169,67 +171,42 @@ public class StatementToTargetExpression implements ASTVisitor {
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;
Optional<Method> findMethod(JavaClassName className, String name, List<TargetType> args) {
return converter.findMethod(converter.compiler.getClass(className), name, args);
}
@Override
public void visit(MethodCall methodCall) {
var receiverType = converter.convert(methodCall.receiver.getType());
var isFunNType = receiverType instanceof TargetFunNType;
var returnType = isFunNType ? TargetType.Object : converter.convert(methodCall.signature.get(methodCall.signature.size() - 1));
var receiverName = new JavaClassName(converter.convert(methodCall.receiver.getType()).name());
var argList = methodCall.signature.stream().map(converter::convert).toList();
argList = argList.subList(0, argList.size() - 1);
Method foundMethod = null;
var isStatic = false;
var isInterface = true;
var signature = methodCall.signatureArguments().stream().map(converter::convert).toList();
var receiverClass = converter.currentClass;
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);
var thisMethod = converter.findMethod(converter.currentClass, methodCall.name, signature);
foundMethod = thisMethod.orElseGet(() -> findMethod(converter.currentClass.getSuperClass().getName(), methodCall.name, signature).orElseThrow());
} else if (!isFunNType) {
receiverClass = converter.compiler.getClass(receiverName);
foundMethod = findMethod(receiverName, methodCall.name, signature).orElseThrow();
}
if (foundMethod != null) {
returnType = TargetType.toTargetType(foundMethod.getReturnType());
argList = Stream.of(foundMethod.getParameterTypes()).map(TargetType::toTargetType).toList();
if (!isFunNType) {
returnType = converter.convert(foundMethod.getReturnType());
argList = foundMethod.getParameterList().getFormalparalist().stream().map(e -> converter.convert(e.getType())).toList();
isStatic = Modifier.isStatic(foundMethod.modifier);
isInterface = receiverClass.isInterface();
}
result = new TargetMethodCall(converter.convert(methodCall.getType()), returnType, argList, converter.convert(methodCall.receiver), methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), receiverType, methodCall.name, false, isFunNType);
result = new TargetMethodCall(converter.convert(methodCall.getType()), returnType, argList, converter.convert(methodCall.receiver), methodCall.getArgumentList().getArguments().stream().map(converter::convert).toList(), receiverType, methodCall.name, isStatic, isInterface);
}
@Override

View File

@ -1,5 +1,7 @@
package de.dhbwstuttgart.target.tree.type;
import de.dhbwstuttgart.syntaxtree.type.RefType;
public sealed interface TargetType
permits TargetExtendsWildcard, TargetGenericType, TargetSpecializedType, TargetSuperWildcard, TargetPrimitiveType {
@ -37,6 +39,20 @@ public sealed interface TargetType
return type;
}
static TargetType toPrimitive(RefType type) {
return switch(type.getName().toString()) {
case "java.lang.Boolean" -> boolean_;
case "java.lang.Character" -> char_;
case "java.lang.Byte" -> byte_;
case "java.lang.Short" -> short_;
case "java.lang.Integer" -> int_;
case "java.lang.Long" -> long_;
case "java.lang.Float" -> float_;
case "java.lang.Double" -> double_;
default -> null;
};
}
static TargetType toTargetType(Class<?> clazz) {
if (clazz.isPrimitive()) {
if (clazz.equals(boolean.class)) return boolean_;

View File

@ -47,7 +47,7 @@ public class TestCodegen {
var result = new HashMap<String, Class<?>>();
for (var file : filenames) {
var sourceFile = compiler.sourceFiles.get(file);
var converter = new ASTToTargetAST(resultSet, sourceFile, classLoader);
var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader);
var classes = compiler.sourceFiles.get(file).getClasses();
result.putAll(classes.stream().map(cli -> {
@ -86,7 +86,7 @@ public class TestCodegen {
var resultSet = compiler.typeInference();
var sourceFile = compiler.sourceFiles.get(file);
var converter = new ASTToTargetAST(resultSet, sourceFile, classLoader);
var converter = new ASTToTargetAST(compiler, resultSet, sourceFile, classLoader);
var classes = compiler.sourceFiles.get(file).getClasses();
var result = classes.stream().map(cli -> {