Fixed chained instVar calls in AssignStatementExpression

This commit is contained in:
Jochen Seyfried 2024-07-04 15:40:07 +02:00
parent edfaa93980
commit 8f55a15aef
2 changed files with 143 additions and 9 deletions

View File

@ -6,7 +6,7 @@ import abstractSyntaxTree.StatementExpression.NewStatementExpression;
import java.util.Objects; import java.util.Objects;
public class SubReceiver implements Node { public class SubReceiver implements Node {
boolean thisExpression; public boolean thisExpression;
public NewStatementExpression newStatementExpression; public NewStatementExpression newStatementExpression;
public String identifier; public String identifier;

View File

@ -85,7 +85,7 @@ public class AssignStatementExpression extends AbstractType implements IExpressi
int counter = 0; int counter = 0;
for (String key : localVars.keySet()) { for (String key : localVars.keySet()) {
if (key.equals(varName)) { if (key.equals(varName)) {
index = counter+1; index = counter + 1;
break; break;
} }
counter++; counter++;
@ -123,6 +123,8 @@ public class AssignStatementExpression extends AbstractType implements IExpressi
} else if (left instanceof InstVarExpression) { } else if (left instanceof InstVarExpression) {
instVar = (InstVarExpression) left; instVar = (InstVarExpression) left;
boolean isLocal = false;
// Load the reference onto the stack // Load the reference onto the stack
// Determine if the reference is this or another object // Determine if the reference is this or another object
if (instVar.receivers.get(0).identifier != null) { if (instVar.receivers.get(0).identifier != null) {
@ -140,12 +142,90 @@ public class AssignStatementExpression extends AbstractType implements IExpressi
throw new Exception("Variable " + instVar.receivers.get(0).identifier + " not found"); throw new Exception("Variable " + instVar.receivers.get(0).identifier + " not found");
} }
mv.visitVarInsn(Opcodes.ALOAD, index); mv.visitVarInsn(Opcodes.ALOAD, index);
isLocal = true;
} else { } else {
// Load "this" onto the stack // Load "this" onto the stack
mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 0);
} }
// Call the codeGen on the right expression which will push the value of the right expression onto the stack // Call the codeGen on the right expression which will push the value of the right expression onto the stack
//right.codeGen(mv, localVars, typeContext, methodContext);
//Now that the base ref is on the stack, I need to get the next field(s) and store the value in the last field
String typeOfPrevious = "";
String currentType = "";
if (instVar.receivers.size() > 0) {
for (int i = 0; i < instVar.receivers.size(); i++) {
if (i == 0) {
//Check if the chain is longer than 1
// If it is not, then we can directly store the value in the field
// If not we have to load the reference of the field on the stack
if (instVar.receivers.size() < 2) {
// Chain is only 1 long, so we can call PUTFIELD directly
//Load the value of the right expression on the stack
right.codeGen(mv, localVars, typeContext, methodContext);
if (isLocal) {
typeOfPrevious = localVars.get(instVar.receivers.get(i).identifier);
} else {
typeOfPrevious = typeContext.get(thisClass).get(instVar.receivers.get(i).identifier);
if (typeOfPrevious == null) {
typeOfPrevious = thisClass;
}
}
currentType = typeContext.get(typeOfPrevious).get(instVar.fieldName);
String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, thisClass);
mv.visitFieldInsn(Opcodes.PUTFIELD, typeOfPrevious, instVar.fieldName, descriptor);
continue;
} else {
if (isLocal) {
currentType = localVars.get(instVar.receivers.get(i).identifier);
} else {
currentType = typeContext.get(thisClass).get(instVar.receivers.get(i).identifier);
}
String descriptor = getFieldDescriptor(currentType, typeContext, instVar.receivers.get(i).identifier, thisClass);
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, instVar.receivers.get(i).identifier, descriptor);
typeOfPrevious = currentType;
continue;
}
}
//Now we have to implement the logic for the following fields in the chain as the above code
// only handles the first field in the chain
// For the following fields I only have to call GETFIELD so I load the next reference onto the stack
// The fields must be present in "typeOfPrevious"
currentType = typeContext.get(typeOfPrevious).get(instVar.receivers.get(i).identifier);
String descriptor = getFieldDescriptor(currentType, typeContext, instVar.receivers.get(i).identifier, typeOfPrevious);
mv.visitFieldInsn(Opcodes.GETFIELD, typeOfPrevious, instVar.receivers.get(i).identifier, descriptor);
typeOfPrevious = currentType;
}
// Now we have the reference of the last field in the chain on the stack
if (instVar.receivers.size() > 1) {
// We can store the value of the right expression in this field
right.codeGen(mv, localVars, typeContext, methodContext);
currentType = typeContext.get(typeOfPrevious).get(instVar.fieldName);
String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, typeOfPrevious);
mv.visitFieldInsn(Opcodes.PUTFIELD, typeOfPrevious, instVar.fieldName, descriptor);
}
} else {
//This is finished and right
// It's for when a field is accessed directly and without a "this."
//Load the value of the right expression on the stack
right.codeGen(mv, localVars, typeContext, methodContext); right.codeGen(mv, localVars, typeContext, methodContext);
// Get the field information // Get the field information
@ -158,6 +238,60 @@ public class AssignStatementExpression extends AbstractType implements IExpressi
mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.thisClass, instVar.fieldName, descriptor); mv.visitFieldInsn(Opcodes.PUTFIELD, instVar.thisClass, instVar.fieldName, descriptor);
} }
} }
}
/*
// Field is called with "this.xxx"
if (instVar.receivers.get(0).thisExpression) {
// If the chain is only 1 long we can directly store the value in the field
// If not we have to load the reference of the field on the stack
if(instVar.receivers.size() > 1) {
// If first receiver is not this check local then fields of thisClass
if (isLocal) {
currentType = localVars.get(instVar.receivers.get(i).identifier);
} else {
currentType = typeContext.get(thisClass).get(instVar.receivers.get(i).identifier);
}
currentType = typeContext.get(thisClass).get(instVar.fieldName);
String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, thisClass);
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, instVar.fieldName, descriptor);
continue;
} else {
// Chain is only 1 long, so we can call PUTFIELD directly
//Load the value of the right expression on the stack
right.codeGen(mv, localVars, typeContext, methodContext);
currentType = typeContext.get(thisClass).get(instVar.fieldName);
String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, thisClass);
mv.visitFieldInsn(Opcodes.PUTFIELD, thisClass, instVar.fieldName, descriptor);
continue;
}
}
// If first receiver is not this check local then fields of thisClass
if (isLocal) {
currentType = localVars.get(instVar.receivers.get(i).identifier);
} else {
currentType = typeContext.get(thisClass).get(instVar.receivers.get(i).identifier);
}
currentType = typeContext.get(typeOfPrevious).get(instVar.fieldName);
String descriptor = getFieldDescriptor(currentType, typeContext, instVar.fieldName, typeOfPrevious);
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass, instVar.fieldName, descriptor);
continue;
}
currentType = typeContext.get(typeOfPrevious).get(instVar.receivers.get(i).identifier);
String descriptor = getFieldDescriptor(currentType, typeContext, instVar.receivers.get(i).identifier, typeOfPrevious);
mv.visitFieldInsn(Opcodes.GETFIELD, typeOfPrevious, instVar.receivers.get(i).identifier, descriptor);
typeOfPrevious = currentType;
} */
private String getFieldDescriptor(String type, HashMap<String, HashMap<String, String>> typeContext, String varName, String classToSearchFieldIn) { private String getFieldDescriptor(String type, HashMap<String, HashMap<String, String>> typeContext, String varName, String classToSearchFieldIn) {
StringBuilder descriptor = new StringBuilder(); StringBuilder descriptor = new StringBuilder();