diff --git a/src/main/java/CodeGen/CodeGenHelper.java b/src/main/java/CodeGen/CodeGenHelper.java new file mode 100644 index 0000000..4c583b4 --- /dev/null +++ b/src/main/java/CodeGen/CodeGenHelper.java @@ -0,0 +1,36 @@ +package CodeGen; + +import abstractSyntaxTree.Expression.SubReceiver; + +import java.util.LinkedHashMap; +import java.util.List; + +public class CodeGenHelper { + + public static String getFieldDescriptor(String type) { + switch (type) { + case "int": + return "I"; + case "boolean": + return "Z"; + case "char": + return "C"; + default: + return "L" + type + ";"; + } + } + + public static int GetLocalVarIndex(LinkedHashMap localVars, String varToSearchFor) { + int index = -1; + int counter = 0; + for (String key : localVars.keySet()) { + if (key.equals(varToSearchFor)) { + index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this" + break; + } + counter++; + } + return index; + } + +} diff --git a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java index 67306b9..1d03201 100644 --- a/src/main/java/abstractSyntaxTree/Class/FieldDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/FieldDecl.java @@ -1,5 +1,6 @@ package abstractSyntaxTree.Class; +import CodeGen.CodeGenHelper; import TypeCheck.AbstractType; import TypeCheck.TypeCheckException; import TypeCheck.TypeCheckHelper; @@ -47,23 +48,11 @@ public class FieldDecl extends AbstractType implements Node { } public void codeGen(ClassWriter cw) { - FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, getFieldDescriptor(), null, null); + String descriptor = CodeGenHelper.getFieldDescriptor(type); + FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, identifier, descriptor, null, null); fv.visitEnd(); } - private String getFieldDescriptor() { - switch (type) { - case "int": - return "I"; - case "boolean": - return "Z"; - case "char": - return "C"; - default: - return "L" + type + ";"; - } - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java index b02020e..0d0b270 100644 --- a/src/main/java/abstractSyntaxTree/Class/MethodDecl.java +++ b/src/main/java/abstractSyntaxTree/Class/MethodDecl.java @@ -1,5 +1,6 @@ package abstractSyntaxTree.Class; +import CodeGen.CodeGenHelper; import TypeCheck.TypeCheckException; import TypeCheck.TypeCheckResult; import abstractSyntaxTree.Node; @@ -91,7 +92,7 @@ public class MethodDecl implements Node { default -> mv.visitInsn(Opcodes.ACONST_NULL); } } - descriptor = getFieldDescriptor(field.type); + descriptor = CodeGenHelper.getFieldDescriptor(field.type); mv.visitFieldInsn(Opcodes.PUTFIELD, classThatContainsMethod, fieldName, descriptor); fieldFound = true; break; @@ -215,19 +216,6 @@ public class MethodDecl implements Node { return descriptor.toString(); } - private String getFieldDescriptor(String type) { - switch (type) { - case "int": - return "I"; - case "boolean": - return "Z"; - case "char": - return "C"; - default: - return "L" + type + ";"; - } - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/abstractSyntaxTree/Datatype/CharDatatype.java b/src/main/java/abstractSyntaxTree/Datatype/CharDatatype.java index 3ed8014..eaf9ad4 100644 --- a/src/main/java/abstractSyntaxTree/Datatype/CharDatatype.java +++ b/src/main/java/abstractSyntaxTree/Datatype/CharDatatype.java @@ -3,6 +3,7 @@ package abstractSyntaxTree.Datatype; import TypeCheck.AbstractType; import TypeCheck.TypeCheckResult; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import java.util.Objects; @@ -21,11 +22,13 @@ public class CharDatatype extends AbstractType implements IDatatype{ @Override public void codeGen(MethodVisitor mv) throws Exception { - - // Possible use of BIPUSH and SIPUSH if the value is small enough - //This saves space in the bytecode which is not very relevant at this point, but could be implemented anyway - - mv.visitLdcInsn((int)value); + if (value <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + value); + } else if (value <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, value); + } else { + mv.visitIntInsn(Opcodes.SIPUSH, value); + } } @Override public boolean equals(Object o) { diff --git a/src/main/java/abstractSyntaxTree/Datatype/IntDatatype.java b/src/main/java/abstractSyntaxTree/Datatype/IntDatatype.java index 6d86b89..2166dca 100644 --- a/src/main/java/abstractSyntaxTree/Datatype/IntDatatype.java +++ b/src/main/java/abstractSyntaxTree/Datatype/IntDatatype.java @@ -21,8 +21,6 @@ public class IntDatatype extends AbstractType implements IDatatype{ @Override public void codeGen(MethodVisitor mv) throws Exception { - - //Example of using BIPUSH and SIPUSH for optimizing bytecode size if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) mv.visitIntInsn(Opcodes.BIPUSH, value); else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) diff --git a/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java b/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java index 01a733d..f7a393f 100644 --- a/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/CharConstantExpression.java @@ -27,7 +27,13 @@ public class CharConstantExpression extends AbstractType implements IExpression{ @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { - mv.visitIntInsn(Opcodes.BIPUSH, (int) value); + if (value <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + value); + } else if (value <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, value); + } else { + mv.visitIntInsn(Opcodes.SIPUSH, value); + } } @Override diff --git a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java index 8eb10dd..934792d 100644 --- a/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/InstVarExpression.java @@ -1,5 +1,6 @@ package abstractSyntaxTree.Expression; +import CodeGen.CodeGenHelper; import TypeCheck.AbstractType; import TypeCheck.TypeCheckException; import TypeCheck.TypeCheckResult; @@ -74,15 +75,7 @@ public class InstVarExpression extends AbstractType implements IExpression { if (i == 0) { // Load the local variable onto the stack - int index = -1; - int counter = 0; - for (String key : localVars.keySet()) { - if (key.equals(this.receivers.get(i).identifier)) { - index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this" - break; - } - counter++; - } + int index = CodeGenHelper.GetLocalVarIndex(localVars, this.receivers.get(i).identifier); if (index == -1) { if (typeContext.get(thisClass).get(this.receivers.get(i).identifier) != null) { @@ -119,15 +112,7 @@ public class InstVarExpression extends AbstractType implements IExpression { else { // Load the local variable onto the stack - int index = -1; - int counter = 0; - for (String key : localVars.keySet()) { - if (key.equals(this.receivers.get(i).identifier)) { - index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this" - break; - } - counter++; - } + int index = CodeGenHelper.GetLocalVarIndex(localVars, this.receivers.get(i).identifier); if (index == -1) { if (typeContext.get(typeOfReciever).get(this.receivers.get(i).identifier) != null) { @@ -157,15 +142,7 @@ public class InstVarExpression extends AbstractType implements IExpression { // Load the field in fieldName // Load the local variable onto the stack - int index = -1; - int counter = 0; - for (String key : localVars.keySet()) { - if (key.equals(fieldName)) { - index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this" - break; - } - counter++; - } + int index = CodeGenHelper.GetLocalVarIndex(localVars, fieldName); if (index == -1) { if (typeContext.get(typeOfReciever).get(fieldName) != null) { @@ -192,15 +169,7 @@ public class InstVarExpression extends AbstractType implements IExpression { } } else if (receivers.get(0).thisExpression) { // Load the local variable or instVar of this onto the stack - int index = -1; - int counter = 0; - for (String key : localVars.keySet()) { - if (key.equals(fieldName)) { - index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this" - break; - } - counter++; - } + int index = CodeGenHelper.GetLocalVarIndex(localVars, fieldName); if (index == -1) { mv.visitVarInsn(Opcodes.ALOAD, 0); diff --git a/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java b/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java index 1541d5a..4b6cd28 100644 --- a/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/IntConstantExpression.java @@ -28,8 +28,15 @@ public class IntConstantExpression extends AbstractType implements IExpression{ @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception { - //TODO: When we are finished this can be done more efficiently - mv.visitLdcInsn(value); + if (value >= -1 && value <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + value); + } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, value); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + mv.visitIntInsn(Opcodes.SIPUSH, value); + } else { + mv.visitLdcInsn(value); + } } @Override diff --git a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java index 772eef6..17089d5 100644 --- a/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java +++ b/src/main/java/abstractSyntaxTree/Expression/LocalVarIdentifier.java @@ -1,5 +1,6 @@ package abstractSyntaxTree.Expression; +import CodeGen.CodeGenHelper; import TypeCheck.AbstractType; import TypeCheck.TypeCheckException; import TypeCheck.TypeCheckHelper; @@ -52,15 +53,7 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{ if (localVars.containsKey(identifier)) { type = localVars.get(identifier); // Find the index of the variable - int index = -1; - int counter = 0; - for (String key : localVars.keySet()) { - if (key.equals(identifier)) { - index = counter + 1; // +1 because the first local variable is at index 1, 0 is used for "this" - break; - } - counter++; - } + int index = CodeGenHelper.GetLocalVarIndex(localVars, identifier); if (index == -1) { throw new Exception("Variable " + identifier + " not found"); @@ -84,25 +77,13 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{ // Load "this" onto the stack mv.visitVarInsn(Opcodes.ALOAD, 0); // Get the field from "this" - mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, identifier, getFieldDescriptor(type)); + String descriptor = CodeGenHelper.getFieldDescriptor(type); + + mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, identifier, descriptor); } else throw new Exception("Variable " + identifier + " not found"); } - //TODO move this to a helper class and remove the doubled code in MethodDecl and in other places - private String getFieldDescriptor(String type) { - switch (type) { - case "int": - return "I"; - case "boolean": - return "Z"; - case "char": - return "C"; - default: - return "L" + type + ";"; - } - } - @Override public TypeCheckResult getTypeCheckResult() { return super.getTypeCheckResult(); diff --git a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java index 30f0465..8913918 100644 --- a/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java +++ b/src/main/java/abstractSyntaxTree/Expression/UnaryExpression.java @@ -2,9 +2,7 @@ package abstractSyntaxTree.Expression; import TypeCheck.AbstractType; import TypeCheck.TypeCheckException; -import TypeCheck.TypeCheckHelper; import TypeCheck.TypeCheckResult; -import abstractSyntaxTree.Datatype.IDatatype; import abstractSyntaxTree.Parameter.ParameterList; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; diff --git a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java index 9f90613..ec57c9b 100644 --- a/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java +++ b/src/main/java/abstractSyntaxTree/Statement/IfElseStatement.java @@ -54,9 +54,6 @@ public class IfElseStatement extends AbstractType implements IStatement{ } - //TODO: There are 2 NOPs and one athrow on the stack between the if-Block and else-Block execution --> I have no idea why - // I think they are generated because of the jump operations below and can not be eliminated - // as they do not negatively impact the execution of the code logic wise we can ignore them @Override public void codeGen(MethodVisitor mv, LinkedHashMap localVars, HashMap> typeContext, HashMap>> methodContext) throws Exception {