First step of code cleanup and refactoring.
Moved the localVarIndex setters into a separate helperClass and optimized bytecodesize in regard to variable pushes
This commit is contained in:
parent
aed7af7c68
commit
3e908293ee
36
src/main/java/CodeGen/CodeGenHelper.java
Normal file
36
src/main/java/CodeGen/CodeGenHelper.java
Normal file
@ -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<String, String> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package abstractSyntaxTree.Class;
|
package abstractSyntaxTree.Class;
|
||||||
|
|
||||||
|
import CodeGen.CodeGenHelper;
|
||||||
import TypeCheck.AbstractType;
|
import TypeCheck.AbstractType;
|
||||||
import TypeCheck.TypeCheckException;
|
import TypeCheck.TypeCheckException;
|
||||||
import TypeCheck.TypeCheckHelper;
|
import TypeCheck.TypeCheckHelper;
|
||||||
@ -47,23 +48,11 @@ public class FieldDecl extends AbstractType implements Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void codeGen(ClassWriter cw) {
|
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();
|
fv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getFieldDescriptor() {
|
|
||||||
switch (type) {
|
|
||||||
case "int":
|
|
||||||
return "I";
|
|
||||||
case "boolean":
|
|
||||||
return "Z";
|
|
||||||
case "char":
|
|
||||||
return "C";
|
|
||||||
default:
|
|
||||||
return "L" + type + ";";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package abstractSyntaxTree.Class;
|
package abstractSyntaxTree.Class;
|
||||||
|
|
||||||
|
import CodeGen.CodeGenHelper;
|
||||||
import TypeCheck.TypeCheckException;
|
import TypeCheck.TypeCheckException;
|
||||||
import TypeCheck.TypeCheckResult;
|
import TypeCheck.TypeCheckResult;
|
||||||
import abstractSyntaxTree.Node;
|
import abstractSyntaxTree.Node;
|
||||||
@ -91,7 +92,7 @@ public class MethodDecl implements Node {
|
|||||||
default -> mv.visitInsn(Opcodes.ACONST_NULL);
|
default -> mv.visitInsn(Opcodes.ACONST_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
descriptor = getFieldDescriptor(field.type);
|
descriptor = CodeGenHelper.getFieldDescriptor(field.type);
|
||||||
mv.visitFieldInsn(Opcodes.PUTFIELD, classThatContainsMethod, fieldName, descriptor);
|
mv.visitFieldInsn(Opcodes.PUTFIELD, classThatContainsMethod, fieldName, descriptor);
|
||||||
fieldFound = true;
|
fieldFound = true;
|
||||||
break;
|
break;
|
||||||
@ -215,19 +216,6 @@ public class MethodDecl implements Node {
|
|||||||
return descriptor.toString();
|
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
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -3,6 +3,7 @@ package abstractSyntaxTree.Datatype;
|
|||||||
import TypeCheck.AbstractType;
|
import TypeCheck.AbstractType;
|
||||||
import TypeCheck.TypeCheckResult;
|
import TypeCheck.TypeCheckResult;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -21,11 +22,13 @@ public class CharDatatype extends AbstractType implements IDatatype{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void codeGen(MethodVisitor mv) throws Exception {
|
public void codeGen(MethodVisitor mv) throws Exception {
|
||||||
|
if (value <= 5) {
|
||||||
// Possible use of BIPUSH and SIPUSH if the value is small enough
|
mv.visitInsn(Opcodes.ICONST_0 + value);
|
||||||
//This saves space in the bytecode which is not very relevant at this point, but could be implemented anyway
|
} else if (value <= Byte.MAX_VALUE) {
|
||||||
|
mv.visitIntInsn(Opcodes.BIPUSH, value);
|
||||||
mv.visitLdcInsn((int)value);
|
} else {
|
||||||
|
mv.visitIntInsn(Opcodes.SIPUSH, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
@ -21,8 +21,6 @@ public class IntDatatype extends AbstractType implements IDatatype{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void codeGen(MethodVisitor mv) throws Exception {
|
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)
|
if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
|
||||||
mv.visitIntInsn(Opcodes.BIPUSH, value);
|
mv.visitIntInsn(Opcodes.BIPUSH, value);
|
||||||
else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
|
else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
|
||||||
|
@ -27,7 +27,13 @@ public class CharConstantExpression extends AbstractType implements IExpression{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
|
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> 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
|
@Override
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package abstractSyntaxTree.Expression;
|
package abstractSyntaxTree.Expression;
|
||||||
|
|
||||||
|
import CodeGen.CodeGenHelper;
|
||||||
import TypeCheck.AbstractType;
|
import TypeCheck.AbstractType;
|
||||||
import TypeCheck.TypeCheckException;
|
import TypeCheck.TypeCheckException;
|
||||||
import TypeCheck.TypeCheckResult;
|
import TypeCheck.TypeCheckResult;
|
||||||
@ -74,15 +75,7 @@ public class InstVarExpression extends AbstractType implements IExpression {
|
|||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
// Load the local variable onto the stack
|
// Load the local variable onto the stack
|
||||||
int index = -1;
|
int index = CodeGenHelper.GetLocalVarIndex(localVars, this.receivers.get(i).identifier);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
if (typeContext.get(thisClass).get(this.receivers.get(i).identifier) != null) {
|
if (typeContext.get(thisClass).get(this.receivers.get(i).identifier) != null) {
|
||||||
@ -119,15 +112,7 @@ public class InstVarExpression extends AbstractType implements IExpression {
|
|||||||
else {
|
else {
|
||||||
|
|
||||||
// Load the local variable onto the stack
|
// Load the local variable onto the stack
|
||||||
int index = -1;
|
int index = CodeGenHelper.GetLocalVarIndex(localVars, this.receivers.get(i).identifier);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
if (typeContext.get(typeOfReciever).get(this.receivers.get(i).identifier) != null) {
|
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 field in fieldName
|
||||||
|
|
||||||
// Load the local variable onto the stack
|
// Load the local variable onto the stack
|
||||||
int index = -1;
|
int index = CodeGenHelper.GetLocalVarIndex(localVars, fieldName);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
if (typeContext.get(typeOfReciever).get(fieldName) != null) {
|
if (typeContext.get(typeOfReciever).get(fieldName) != null) {
|
||||||
@ -192,15 +169,7 @@ public class InstVarExpression extends AbstractType implements IExpression {
|
|||||||
}
|
}
|
||||||
} else if (receivers.get(0).thisExpression) {
|
} else if (receivers.get(0).thisExpression) {
|
||||||
// Load the local variable or instVar of this onto the stack
|
// Load the local variable or instVar of this onto the stack
|
||||||
int index = -1;
|
int index = CodeGenHelper.GetLocalVarIndex(localVars, fieldName);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
|
@ -28,8 +28,15 @@ public class IntConstantExpression extends AbstractType implements IExpression{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
|
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
|
||||||
//TODO: When we are finished this can be done more efficiently
|
if (value >= -1 && value <= 5) {
|
||||||
mv.visitLdcInsn(value);
|
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
|
@Override
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package abstractSyntaxTree.Expression;
|
package abstractSyntaxTree.Expression;
|
||||||
|
|
||||||
|
import CodeGen.CodeGenHelper;
|
||||||
import TypeCheck.AbstractType;
|
import TypeCheck.AbstractType;
|
||||||
import TypeCheck.TypeCheckException;
|
import TypeCheck.TypeCheckException;
|
||||||
import TypeCheck.TypeCheckHelper;
|
import TypeCheck.TypeCheckHelper;
|
||||||
@ -52,15 +53,7 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{
|
|||||||
if (localVars.containsKey(identifier)) {
|
if (localVars.containsKey(identifier)) {
|
||||||
type = localVars.get(identifier);
|
type = localVars.get(identifier);
|
||||||
// Find the index of the variable
|
// Find the index of the variable
|
||||||
int index = -1;
|
int index = CodeGenHelper.GetLocalVarIndex(localVars, identifier);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
throw new Exception("Variable " + identifier + " not found");
|
throw new Exception("Variable " + identifier + " not found");
|
||||||
@ -84,25 +77,13 @@ public class LocalVarIdentifier extends AbstractType implements IExpression{
|
|||||||
// Load "this" onto the stack
|
// Load "this" onto the stack
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
// Get the field from "this"
|
// 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
|
} else
|
||||||
throw new Exception("Variable " + identifier + " not found");
|
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
|
@Override
|
||||||
public TypeCheckResult getTypeCheckResult() {
|
public TypeCheckResult getTypeCheckResult() {
|
||||||
return super.getTypeCheckResult();
|
return super.getTypeCheckResult();
|
||||||
|
@ -2,9 +2,7 @@ package abstractSyntaxTree.Expression;
|
|||||||
|
|
||||||
import TypeCheck.AbstractType;
|
import TypeCheck.AbstractType;
|
||||||
import TypeCheck.TypeCheckException;
|
import TypeCheck.TypeCheckException;
|
||||||
import TypeCheck.TypeCheckHelper;
|
|
||||||
import TypeCheck.TypeCheckResult;
|
import TypeCheck.TypeCheckResult;
|
||||||
import abstractSyntaxTree.Datatype.IDatatype;
|
|
||||||
import abstractSyntaxTree.Parameter.ParameterList;
|
import abstractSyntaxTree.Parameter.ParameterList;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
@ -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
|
@Override
|
||||||
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
|
public void codeGen(MethodVisitor mv, LinkedHashMap<String, String> localVars, HashMap<String, HashMap<String, String>> typeContext, HashMap<String, HashMap<String, HashMap<String, ParameterList>>> methodContext) throws Exception {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user