From b6f444b0f7b5606e0be6261e9bb871e2d102a1bc Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 15 Apr 2011 18:59:57 +0200 Subject: [PATCH] introduce StackValue.store(); use it to implement write access to fields and arrays --- .../jet/codegen/ExpressionCodegen.java | 46 +++------- .../org/jetbrains/jet/codegen/StackValue.java | 91 ++++++++++++++----- .../jet/codegen/NamespaceGenTest.java | 1 + 3 files changed, 81 insertions(+), 57 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 186b0446c23..31fdd4a3c53 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -62,7 +62,7 @@ public class ExpressionCodegen extends JetVisitor { } } - private void genToStack(JetExpression expr) { + private void genToJVMStack(JetExpression expr) { gen(expr, expressionType(expr)); } @@ -349,14 +349,11 @@ public class ExpressionCodegen extends JetVisitor { PsiField psiField = (PsiField) declaration; final String owner = JetTypeMapper.jvmName(psiField.getContainingClass()); final Type fieldType = psiTypeToAsm(psiField.getType()); - if (psiField.hasModifierProperty(PsiModifier.STATIC)) { - v.visitFieldInsn(Opcodes.GETSTATIC, owner, psiField.getName(), fieldType.getDescriptor()); - } - else { + final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC); + if (!isStatic) { 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 { int index = myMap.getIndex(descriptor); @@ -553,7 +550,7 @@ public class ExpressionCodegen extends JetVisitor { @Override public void visitSafeQualifiedExpression(JetSafeQualifiedExpression expression) { - genToStack(expression.getReceiverExpression()); + genToJVMStack(expression.getReceiverExpression()); Label ifnull = new Label(); Label end = new Label(); v.dup(); @@ -773,32 +770,16 @@ public class ExpressionCodegen extends JetVisitor { } private void generateAssignmentExpression(JetBinaryExpression expression) { - if (expression.getLeft() instanceof JetArrayAccessExpression) { - final JetArrayAccessExpression arrayAccess = (JetArrayAccessExpression) expression.getLeft(); - final Type arrayType = expressionType(arrayAccess.getArrayExpression()); - if (arrayType.getSort() == Type.ARRAY) { - gen(arrayAccess.getArrayExpression(), arrayType); - 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()); + int oldStackSize = myStack.size(); + gen(expression.getLeft()); + genToJVMStack(expression.getRight()); + if (myStack.size() != oldStackSize+1) { + throw new UnsupportedClassVersionError("generated something which doesn't seem to be an lvalue"); } + myStack.pop().store(v); } + private void generateAugmentedAssignment(JetBinaryExpression expression) { final JetExpression lhs = expression.getLeft(); if (lhs instanceof JetReferenceExpression) { @@ -995,8 +976,7 @@ public class ExpressionCodegen extends JetVisitor { gen(array, arrayType); generateArrayIndex(expression); final Type elementType = arrayType.getElementType(); - v.aload(elementType); - myStack.push(StackValue.onStack(elementType)); + myStack.push(StackValue.arrayElement(elementType)); } else { throw new UnsupportedOperationException("array access to non-Java arrays is not supported"); diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index 57e3380c074..b446773d0bb 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -19,6 +19,25 @@ public abstract class StackValue { 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) { return new Local(index, type); } @@ -40,7 +59,13 @@ public abstract class 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) { if (type == Type.INT_TYPE) { @@ -135,14 +160,8 @@ public abstract class StackValue { } @Override - public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { - put(Type.INT_TYPE, v); - if (jumpIfFalse) { - v.ifeq(label); - } - else { - v.ifne(label); - } + public void store(InstructionAdapter v) { + v.store(index, this.type); } } @@ -165,21 +184,6 @@ public abstract class StackValue { 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 { @@ -312,4 +316,43 @@ public abstract class StackValue { 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()); + } + } } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 5d473846373..6048dd482e6 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -313,6 +313,7 @@ public class NamespaceGenTest extends CodegenTestCase { public void testArrayWrite() throws Exception { loadText("fun foo(c: Array) { c[0] = \"jet\"; }"); + System.out.println(generateToText()); final Method main = generateFunction(); String[] array = new String[] { null }; main.invoke(null, new Object[] { array });