mirror of
https://github.com/JonathanFleischmann/CompilerULTIMATE.git
synced 2024-12-27 08:58:02 +00:00
Merge branch 'main' of https://github.com/JonathanFleischmann/CompilerULTIMATE
This commit is contained in:
commit
7b53346580
Binary file not shown.
@ -98,9 +98,7 @@ public class Compiler {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassWithConstructor.java",
|
||||
"src/main/resources/JavaTestfiles/ClassWithConstructorAndMethodCall.java",
|
||||
"src/main/resources/JavaTestfiles/ComplexClass.java"),
|
||||
List.of("ClassWithConstructor","ClassWithConstructorAndMethodCall","ComplexClass"));
|
||||
generateByteCodeFileFromFile(List.of("src/main/resources/JavaTestfiles/ClassCanBeBytecoded.java"),
|
||||
List.of("ClassCanBeBytecoded"));
|
||||
}
|
||||
}
|
||||
|
@ -15,23 +15,20 @@ public class MethodContext {
|
||||
public record LocalVariable(String name, int index, Type type) {
|
||||
}
|
||||
|
||||
private Label startLabel;
|
||||
private Label endLabel;
|
||||
private MethodVisitor mv;
|
||||
private ClassContext classContext;
|
||||
private final ClassContext classContext;
|
||||
private int localVarIndex = 0;
|
||||
private final Map<String, LocalVariable> variableIndex = new HashMap<>();
|
||||
private Stack<Integer> stack = new Stack<>();
|
||||
private int maxStack = 0;
|
||||
//used to jump out of loops with break
|
||||
private final Stack<Label> breakLabels = new Stack<>();
|
||||
|
||||
public MethodContext(ClassContext classContext, MethodVisitor mv) {
|
||||
startLabel = new Label();
|
||||
endLabel = new Label();
|
||||
this.mv = mv;
|
||||
this.classContext = classContext;
|
||||
registerVariable("this", classContext.getType());
|
||||
mv.visitCode();
|
||||
mv.visitLabel(startLabel);
|
||||
}
|
||||
|
||||
public void registerVariable(String name, Type type) {
|
||||
@ -79,7 +76,6 @@ public class MethodContext {
|
||||
}
|
||||
|
||||
public void wrapUp() {
|
||||
mv.visitLabel(endLabel);
|
||||
System.out.println("maxStack: " + maxStack + " localVarIndex: " + localVarIndex);
|
||||
mv.visitMaxs(maxStack, localVarIndex);
|
||||
mv.visitEnd();
|
||||
|
@ -82,17 +82,15 @@ public class TypedAssignment implements TypedStatement {
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodContext ctx) {
|
||||
if(value instanceof TypedNew) {
|
||||
if(value instanceof TypedNew || value instanceof TypedMethodCall) {
|
||||
value.codeGen(ctx);
|
||||
getOwnerChain(ctx);
|
||||
} else {
|
||||
ctx.pushStack("this");
|
||||
getOwnerChain(ctx);
|
||||
value.codeGen(ctx);
|
||||
}
|
||||
|
||||
|
||||
//save value in field
|
||||
//save value
|
||||
if (location.getField()) {
|
||||
|
||||
String receiver = ctx.getClassContext().getName();
|
||||
@ -101,22 +99,25 @@ public class TypedAssignment implements TypedStatement {
|
||||
}
|
||||
ctx.getMv().visitFieldInsn(Opcodes.PUTFIELD, receiver, location.getName(), value.getType().getDescriptor());
|
||||
System.out.println("PUTFIELD: " + receiver + " " + location.getName() + " " + value.getType().getDescriptor());
|
||||
ctx.popStack();
|
||||
} else {
|
||||
if(value.getType().getKind() == Type.Kind.REFERENCE) {
|
||||
System.out.println("ASTORE " + ctx.getLocalVar(location.getName()).get().index());
|
||||
ctx.getMv().visitVarInsn(Opcodes.ASTORE, ctx.getLocalVar(location.getName()).get().index());
|
||||
} else {
|
||||
System.out.println("ISTORE " + ctx.getLocalVar(location.getName()).get().index());
|
||||
ctx.getMv().visitVarInsn(Opcodes.ISTORE, ctx.getLocalVar(location.getName()).get().index());
|
||||
}
|
||||
}
|
||||
//ctx.popStack();
|
||||
//ctx.popStack();
|
||||
ctx.popStack();
|
||||
}
|
||||
|
||||
private void getOwnerChain(MethodContext ctx) {
|
||||
if (location.getRecursiveOwnerChain() != null) {
|
||||
location.getRecursiveOwnerChain().codeGen(ctx);
|
||||
ctx.pushAnonToStack();
|
||||
}
|
||||
if (location.getRecursiveOwnerChain() == null && location.getField()) {
|
||||
ctx.pushStack("this");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -206,5 +206,7 @@ public class TypedBinary implements TypedExpression {
|
||||
}
|
||||
}
|
||||
ctx.popStack();
|
||||
ctx.popStack();
|
||||
ctx.pushAnonToStack();
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import de.maishai.typedast.MethodContext;
|
||||
import de.maishai.typedast.TypedStatement;
|
||||
import de.maishai.typedast.Type;
|
||||
import lombok.Data;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
@Data
|
||||
public class TypedBreak implements TypedStatement {
|
||||
@ -17,6 +18,9 @@ public class TypedBreak implements TypedStatement {
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodContext ctx) {
|
||||
|
||||
if (ctx.getBreakLabels().isEmpty()) {
|
||||
throw new RuntimeException("Break statement outside of loop");
|
||||
}
|
||||
ctx.getMv().visitJumpInsn(Opcodes.GOTO, ctx.getBreakLabels().pop());
|
||||
}
|
||||
}
|
||||
|
@ -205,38 +205,4 @@ public class TypedClass implements TypedNode {
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
TypedClass c = new TypedClass();
|
||||
c.setClassName("SomeClass");
|
||||
|
||||
//Fields
|
||||
TypedDeclaration f1 = new TypedDeclaration("someNumber", Type.INT);
|
||||
TypedDeclaration f2 = new TypedDeclaration("someChar", Type.CHAR);
|
||||
c.typedDeclarations = List.of(f1, f2);
|
||||
|
||||
//Constructors
|
||||
TypedConstructor constructor = new TypedConstructor("SomeClass", List.of(new TypedParameter("test", Type.INT)), new TypedBlock(new ArrayList<>(), new ArrayList<>()));
|
||||
c.typedConstructors = List.of(constructor);
|
||||
|
||||
//Methods
|
||||
c.typedMethods = new ArrayList<>();
|
||||
TypedMethod m = new TypedMethod();
|
||||
m.setName("someMethod");
|
||||
m.setReturnType(Type.INT);
|
||||
m.setTypedParameters(List.of(new TypedParameter("test", Type.INT)));
|
||||
TypedIfElse ifs = new TypedIfElse();
|
||||
TypedBinary cond = new TypedBinary();
|
||||
cond.setOp(Operator.GT);
|
||||
//cond.setLeft(??);
|
||||
cond.setRight(new TypedIntLiteral(12));
|
||||
ifs.setTypedCon(cond);
|
||||
m.setTypedBlock(new TypedBlock(List.of(), List.of(ifs, new TypedReturn())));
|
||||
c.typedMethods.add(m);
|
||||
|
||||
//codeGen
|
||||
byte[] code = c.codeGen();
|
||||
CodeGenUtils.writeClassfile(code, "SomeClass");
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package de.maishai.typedast.typedclass;
|
||||
import de.maishai.ast.records.*;
|
||||
import de.maishai.typedast.*;
|
||||
import lombok.Data;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
|
||||
|
||||
@ -33,6 +35,19 @@ public class TypedDoWhile implements TypedStatement {
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodContext ctx) {
|
||||
Label loopStart = new Label();
|
||||
Label loopEnd = new Label();
|
||||
ctx.getBreakLabels().push(loopEnd);
|
||||
|
||||
ctx.getMv().visitLabel(loopStart);
|
||||
|
||||
typedBlock.codeGen(ctx);
|
||||
|
||||
cond.codeGen(ctx);
|
||||
|
||||
ctx.getMv().visitJumpInsn(Opcodes.IFNE, loopStart);
|
||||
ctx.popStack();
|
||||
|
||||
ctx.getMv().visitLabel(loopEnd);
|
||||
}
|
||||
}
|
||||
|
@ -108,16 +108,29 @@ public class TypedFieldVarAccess implements TypedExpression {
|
||||
public void codeGen(MethodContext ctx) {
|
||||
if (recursiveOwnerChain != null) {
|
||||
recursiveOwnerChain.codeGen(ctx);
|
||||
ctx.popStack();
|
||||
}
|
||||
if (field && recursiveOwnerChain == null) {
|
||||
ctx.pushStack("this");
|
||||
ctx.popStack();
|
||||
}
|
||||
if (field) {
|
||||
ctx.getMv().visitFieldInsn(Opcodes.GETFIELD, recursiveOwnerChain.getType().getReference(), name, type.getDescriptor());
|
||||
String ownerChainName;
|
||||
if (recursiveOwnerChain != null) {
|
||||
ownerChainName = recursiveOwnerChain.getType().getReference();
|
||||
} else {
|
||||
if (type.getKind() == Type.Kind.REFERENCE) {
|
||||
ownerChainName = type.getReference();
|
||||
} else {
|
||||
ownerChainName = ctx.getClassContext().getName();
|
||||
}
|
||||
}
|
||||
ctx.getMv().visitFieldInsn(Opcodes.GETFIELD, ownerChainName, name, type.getDescriptor());
|
||||
} else {
|
||||
int loadOpcode = type.getKind() == Type.Kind.REFERENCE ? Opcodes.ALOAD : Opcodes.ILOAD;
|
||||
ctx.getMv().visitVarInsn(loadOpcode, ctx.getLocalVar(name).get().index());
|
||||
System.out.println(loadOpcode == Opcodes.ALOAD ? "ALOAD " + ctx.getLocalVar(name).get().index() : "ILOAD " + ctx.getLocalVar(name).get().index());
|
||||
}
|
||||
ctx.pushAnonToStack();
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import de.maishai.typedast.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
|
||||
|
||||
@ -42,6 +44,21 @@ public class TypedFor implements TypedStatement {
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodContext ctx) {
|
||||
Label loopStart = new Label();
|
||||
Label loopUpdate = new Label();
|
||||
Label loopEnd = new Label();
|
||||
ctx.getBreakLabels().push(loopEnd);
|
||||
|
||||
assign.codeGen(ctx);
|
||||
ctx.getMv().visitLabel(loopStart);
|
||||
cond.codeGen(ctx);
|
||||
ctx.getMv().visitJumpInsn(Opcodes.IFEQ, loopEnd);
|
||||
ctx.popStack();
|
||||
|
||||
typedBlock.codeGen(ctx);
|
||||
ctx.getMv().visitLabel(loopUpdate);
|
||||
inc.codeGen(ctx);
|
||||
ctx.getMv().visitJumpInsn(Opcodes.GOTO, loopStart);
|
||||
ctx.getMv().visitLabel(loopEnd);
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ public class TypedIfElse implements TypedStatement {
|
||||
Label end = new Label();
|
||||
typedCon.codeGen(ctx);
|
||||
ctx.getMv().visitJumpInsn(Opcodes.IFEQ, falseLabel);
|
||||
ctx.popStack();
|
||||
ifTypedBlock.codeGen(ctx);
|
||||
ctx.getMv().visitJumpInsn(Opcodes.GOTO, end);
|
||||
|
||||
|
@ -6,6 +6,7 @@ import de.maishai.typedast.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -85,6 +86,31 @@ public class TypedMethodCall implements TypedExpression, TypedStatement {
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodContext ctx) {
|
||||
getOwnerChain(ctx);
|
||||
for (TypedExpression arg : args) {
|
||||
arg.codeGen(ctx);
|
||||
}
|
||||
String descriptor = CodeGenUtils.generateDescriptor(args.stream().map(TypedExpression::getType).toList(), type);
|
||||
String methodOwnerClass;
|
||||
if (recipient.getRecursiveOwnerChain() == null) {
|
||||
methodOwnerClass = ctx.getClassContext().getName();
|
||||
} else {
|
||||
methodOwnerClass = recipient.getRecursiveOwnerChain().getType().getReference();
|
||||
}
|
||||
ctx.getMv().visitMethodInsn(Opcodes.INVOKEVIRTUAL, methodOwnerClass, recipient.getName(), descriptor, false);
|
||||
System.out.println("INVOKEVIRTUAL " + methodOwnerClass + " " + recipient.getName() + " " + descriptor);
|
||||
ctx.popStack(); // pop the owner
|
||||
for (TypedExpression arg : args) {
|
||||
ctx.popStack();
|
||||
}
|
||||
ctx.pushAnonToStack();
|
||||
}
|
||||
|
||||
private void getOwnerChain(MethodContext ctx) {
|
||||
if (recipient.getRecursiveOwnerChain() != null) {
|
||||
recipient.getRecursiveOwnerChain().codeGen(ctx);
|
||||
} else {
|
||||
ctx.pushStack("this");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,11 +57,6 @@ public class TypedNew implements TypedExpression, TypedStatement {
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodContext ctx) {
|
||||
//pop the stack
|
||||
//ctx.popStack();
|
||||
//ctx.getMv().visitInsn(Opcodes.POP);
|
||||
//System.out.println("Popped stack");
|
||||
|
||||
ctx.getMv().visitTypeInsn(Opcodes.NEW, type.getReference());
|
||||
System.out.println("NEW " + type.getReference());
|
||||
ctx.pushAnonToStack();
|
||||
@ -72,6 +67,9 @@ public class TypedNew implements TypedExpression, TypedStatement {
|
||||
arg.codeGen(ctx);
|
||||
}
|
||||
ctx.getMv().visitMethodInsn(Opcodes.INVOKESPECIAL, type.getReference(), "<init>", CodeGenUtils.generateDescriptor(args.stream().map(TypedExpression::getType).toList(), Type.VOID), false);
|
||||
for (TypedExpression arg : args) {
|
||||
ctx.popStack();
|
||||
}
|
||||
System.out.println("INVOKESPECIAL " + type.getReference() + "<init> " + CodeGenUtils.generateDescriptor(args.stream().map(TypedExpression::getType).toList(), Type.VOID));
|
||||
}
|
||||
}
|
||||
|
@ -49,13 +49,15 @@ public class TypedReturn implements TypedStatement {
|
||||
public void codeGen(MethodContext ctx) {
|
||||
if (ret == null) {
|
||||
ctx.getMv().visitInsn(Opcodes.RETURN);
|
||||
System.out.println("RETURN");
|
||||
} else {
|
||||
System.out.println("return: " + ret);
|
||||
ret.codeGen(ctx);
|
||||
if (ret.getType().getKind() != Type.Kind.REFERENCE) {
|
||||
ctx.getMv().visitInsn(Opcodes.IRETURN);
|
||||
System.out.println("IRETURN");
|
||||
} else {
|
||||
ctx.getMv().visitInsn(Opcodes.ARETURN);
|
||||
System.out.println("ARETURN");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,9 @@ package de.maishai.typedast.typedclass;
|
||||
import de.maishai.ast.records.*;
|
||||
import de.maishai.typedast.*;
|
||||
import lombok.Data;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
|
||||
import static de.maishai.typedast.Help.TypedExpressionHelp.convertExpression;
|
||||
|
||||
@ -33,6 +36,17 @@ public class TypedWhile implements TypedStatement {
|
||||
|
||||
@Override
|
||||
public void codeGen(MethodContext ctx) {
|
||||
Label loopStart = new Label();
|
||||
Label loopEnd = new Label();
|
||||
ctx.getBreakLabels().push(loopEnd);
|
||||
|
||||
ctx.getMv().visitLabel(loopStart);
|
||||
cond.codeGen(ctx);
|
||||
|
||||
ctx.getMv().visitJumpInsn(Opcodes.IFEQ, loopEnd);
|
||||
ctx.popStack();
|
||||
typedBlock.codeGen(ctx);
|
||||
ctx.getMv().visitJumpInsn(Opcodes.GOTO, loopStart);
|
||||
ctx.getMv().visitLabel(loopEnd);
|
||||
}
|
||||
}
|
||||
|
17
src/main/resources/JavaTestfiles/ClassCanBeBytecoded.java
Normal file
17
src/main/resources/JavaTestfiles/ClassCanBeBytecoded.java
Normal file
@ -0,0 +1,17 @@
|
||||
public class ClassCanBeBytecoded {
|
||||
public ClassCanBeBytecoded c;
|
||||
public int x;
|
||||
public ClassCanBeBytecoded() {
|
||||
}
|
||||
|
||||
|
||||
public int test(int var1) {
|
||||
for (int i = 0; i < 12; i = i + 1) {
|
||||
var1 = this.c.c.c.c.x + this.x;
|
||||
if (var1 * 3 == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return var1;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user