introduce StackValue.store(); use it to implement write access to fields and arrays

This commit is contained in:
Dmitry Jemerov
2011-04-15 18:59:57 +02:00
parent 9b0a9b71a2
commit b6f444b0f7
3 changed files with 81 additions and 57 deletions
@@ -62,7 +62,7 @@ public class ExpressionCodegen extends JetVisitor {
} }
} }
private void genToStack(JetExpression expr) { private void genToJVMStack(JetExpression expr) {
gen(expr, expressionType(expr)); gen(expr, expressionType(expr));
} }
@@ -349,14 +349,11 @@ public class ExpressionCodegen extends JetVisitor {
PsiField psiField = (PsiField) declaration; PsiField psiField = (PsiField) declaration;
final String owner = JetTypeMapper.jvmName(psiField.getContainingClass()); final String owner = JetTypeMapper.jvmName(psiField.getContainingClass());
final Type fieldType = psiTypeToAsm(psiField.getType()); final Type fieldType = psiTypeToAsm(psiField.getType());
if (psiField.hasModifierProperty(PsiModifier.STATIC)) { final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
v.visitFieldInsn(Opcodes.GETSTATIC, owner, psiField.getName(), fieldType.getDescriptor()); if (!isStatic) {
}
else {
ensureReceiverOnStack(expression); ensureReceiverOnStack(expression);
v.visitFieldInsn(Opcodes.GETFIELD, owner, psiField.getName(), fieldType.getDescriptor());
} }
myStack.push(StackValue.onStack(fieldType)); myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic));
} }
else { else {
int index = myMap.getIndex(descriptor); int index = myMap.getIndex(descriptor);
@@ -553,7 +550,7 @@ public class ExpressionCodegen extends JetVisitor {
@Override @Override
public void visitSafeQualifiedExpression(JetSafeQualifiedExpression expression) { public void visitSafeQualifiedExpression(JetSafeQualifiedExpression expression) {
genToStack(expression.getReceiverExpression()); genToJVMStack(expression.getReceiverExpression());
Label ifnull = new Label(); Label ifnull = new Label();
Label end = new Label(); Label end = new Label();
v.dup(); v.dup();
@@ -773,32 +770,16 @@ public class ExpressionCodegen extends JetVisitor {
} }
private void generateAssignmentExpression(JetBinaryExpression expression) { private void generateAssignmentExpression(JetBinaryExpression expression) {
if (expression.getLeft() instanceof JetArrayAccessExpression) { int oldStackSize = myStack.size();
final JetArrayAccessExpression arrayAccess = (JetArrayAccessExpression) expression.getLeft(); gen(expression.getLeft());
final Type arrayType = expressionType(arrayAccess.getArrayExpression()); genToJVMStack(expression.getRight());
if (arrayType.getSort() == Type.ARRAY) { if (myStack.size() != oldStackSize+1) {
gen(arrayAccess.getArrayExpression(), arrayType); throw new UnsupportedClassVersionError("generated something which doesn't seem to be an lvalue");
generateArrayIndex(arrayAccess);
final Type elementType = arrayType.getElementType();
gen(expression.getRight(), elementType);
v.astore(elementType);
}
else {
throw new UnsupportedOperationException("Don't know how to generate assignment to non-Java array " + expression.getLeft().getText());
}
}
else if (expression.getLeft() instanceof JetReferenceExpression) {
final JetReferenceExpression lhs = (JetReferenceExpression) expression.getLeft();
final int index = indexOfLocal(lhs);
final Type type = typeMapper.mapType(bindingContext.getExpressionType(lhs));
gen(expression.getRight(), type);
v.store(index, type);
}
else {
throw new UnsupportedOperationException("Don't know how to generate assignment to " + expression.getLeft().getText());
} }
myStack.pop().store(v);
} }
private void generateAugmentedAssignment(JetBinaryExpression expression) { private void generateAugmentedAssignment(JetBinaryExpression expression) {
final JetExpression lhs = expression.getLeft(); final JetExpression lhs = expression.getLeft();
if (lhs instanceof JetReferenceExpression) { if (lhs instanceof JetReferenceExpression) {
@@ -995,8 +976,7 @@ public class ExpressionCodegen extends JetVisitor {
gen(array, arrayType); gen(array, arrayType);
generateArrayIndex(expression); generateArrayIndex(expression);
final Type elementType = arrayType.getElementType(); final Type elementType = arrayType.getElementType();
v.aload(elementType); myStack.push(StackValue.arrayElement(elementType));
myStack.push(StackValue.onStack(elementType));
} }
else { else {
throw new UnsupportedOperationException("array access to non-Java arrays is not supported"); throw new UnsupportedOperationException("array access to non-Java arrays is not supported");
@@ -19,6 +19,25 @@ public abstract class StackValue {
public abstract void put(Type type, InstructionAdapter v); public abstract void put(Type type, InstructionAdapter v);
public void store(InstructionAdapter v) {
throw new UnsupportedOperationException("cannot store to value " + this);
}
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
if (this.type == Type.BOOLEAN_TYPE) {
put(Type.BOOLEAN_TYPE, v);
if (jumpIfFalse) {
v.ifeq(label);
}
else {
v.ifne(label);
}
}
else {
throw new UnsupportedOperationException("can't generate a cond jump for a non-boolean value");
}
}
public static StackValue local(int index, Type type) { public static StackValue local(int index, Type type) {
return new Local(index, type); return new Local(index, type);
} }
@@ -40,7 +59,13 @@ public abstract class StackValue {
return new Invert(stackValue); return new Invert(stackValue);
} }
public abstract void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v); public static StackValue arrayElement(Type type) {
return new ArrayElement(type);
}
public static StackValue field(Type type, String owner, String name, boolean isStatic) {
return new Field(type, owner, name, isStatic);
}
private static void box(final Type type, InstructionAdapter v) { private static void box(final Type type, InstructionAdapter v) {
if (type == Type.INT_TYPE) { if (type == Type.INT_TYPE) {
@@ -135,14 +160,8 @@ public abstract class StackValue {
} }
@Override @Override
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { public void store(InstructionAdapter v) {
put(Type.INT_TYPE, v); v.store(index, this.type);
if (jumpIfFalse) {
v.ifeq(label);
}
else {
v.ifne(label);
}
} }
} }
@@ -165,21 +184,6 @@ public abstract class StackValue {
coerce(type, v); coerce(type, v);
} }
} }
@Override
public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
if (this.type == Type.BOOLEAN_TYPE) {
if (jumpIfFalse) {
v.ifeq(label);
}
else {
v.ifne(label);
}
}
else {
throw new UnsupportedOperationException("can't generate a cond jump for a non-boolean value on stack");
}
}
} }
public static class Constant extends StackValue { public static class Constant extends StackValue {
@@ -312,4 +316,43 @@ public abstract class StackValue {
myOperand.condJump(label, !jumpIfFalse, v); myOperand.condJump(label, !jumpIfFalse, v);
} }
} }
private static class ArrayElement extends StackValue {
public ArrayElement(Type type) {
super(type);
}
@Override
public void put(Type type, InstructionAdapter v) {
v.aload(type); // assumes array and index are on the stack
}
@Override
public void store(InstructionAdapter v) {
v.astore(type); // assumes array and index are on the stack
}
}
private static class Field extends StackValue {
private final String owner;
private final String name;
private final boolean isStatic;
public Field(Type type, String owner, String name, boolean isStatic) {
super(type);
this.owner = owner;
this.name = name;
this.isStatic = isStatic;
}
@Override
public void put(Type type, InstructionAdapter v) {
v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, this.type.getDescriptor());
}
@Override
public void store(InstructionAdapter v) {
v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor());
}
}
} }
@@ -313,6 +313,7 @@ public class NamespaceGenTest extends CodegenTestCase {
public void testArrayWrite() throws Exception { public void testArrayWrite() throws Exception {
loadText("fun foo(c: Array<String>) { c[0] = \"jet\"; }"); loadText("fun foo(c: Array<String>) { c[0] = \"jet\"; }");
System.out.println(generateToText());
final Method main = generateFunction(); final Method main = generateFunction();
String[] array = new String[] { null }; String[] array = new String[] { null };
main.invoke(null, new Object[] { array }); main.invoke(null, new Object[] { array });