diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 31fdd4a3c53..f1906a2a0b5 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -66,6 +66,15 @@ public class ExpressionCodegen extends JetVisitor { gen(expr, expressionType(expr)); } + private StackValue generateIntermediateValue(final JetExpression baseExpression) { + int oldStackSize = myStack.size(); + gen(baseExpression); + if (myStack.size() != oldStackSize+1) { + throw new UnsupportedOperationException("intermediate value expected"); + } + return myStack.pop(); + } + @Override public void visitExpression(JetExpression expression) { throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented"); @@ -770,16 +779,11 @@ public class ExpressionCodegen extends JetVisitor { } private void generateAssignmentExpression(JetBinaryExpression expression) { - int oldStackSize = myStack.size(); - gen(expression.getLeft()); + StackValue stackValue = generateIntermediateValue(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); + stackValue.store(v, false); } - private void generateAugmentedAssignment(JetBinaryExpression expression) { final JetExpression lhs = expression.getLeft(); if (lhs instanceof JetReferenceExpression) { @@ -880,50 +884,47 @@ public class ExpressionCodegen extends JetVisitor { return true; } else if (op.getName().equals("inc") || op.getName().equals("dec")) { - final int index = generateIncrement(op, asmType, operand); - myStack.push(StackValue.local(index, asmType)); + myStack.push(generateIncrement(op, asmType, operand)); return true; } return false; } private void generateNot(JetPrefixExpression expression) { - int oldStackSize = myStack.size(); - gen(expression.getBaseExpression()); - assert myStack.size() == oldStackSize+1; - myStack.set(myStack.size()-1, StackValue.not(myStack.get(myStack.size() - 1))); + final StackValue stackValue = generateIntermediateValue(expression.getBaseExpression()); + myStack.push(StackValue.not(stackValue)); } - private int generateIncrement(DeclarationDescriptor op, Type asmType, JetExpression operand) { - if (!(operand instanceof JetReferenceExpression)) { - throw new UnsupportedOperationException("cannot increment or decrement a non-lvalue"); - } + private StackValue generateIncrement(DeclarationDescriptor op, Type asmType, JetExpression operand) { int increment = op.getName().equals("inc") ? 1 : -1; - final int index = indexOfLocal((JetReferenceExpression) operand); - if (index < 0) { - throw new UnsupportedOperationException("don't know how to increment or decrement something which is not a local var"); + if (operand instanceof JetReferenceExpression) { + final int index = indexOfLocal((JetReferenceExpression) operand); + if (index < 0) { + throw new UnsupportedOperationException("don't know how to increment or decrement something which is not a local var"); + } + if (isIntPrimitive(asmType)) { + v.iinc(index, increment); + return StackValue.local(index, asmType); + } } - if (isIntPrimitive(asmType)) { - v.iinc(index, increment); + StackValue value = generateIntermediateValue(operand); + value.put(asmType, v); + if (asmType == Type.LONG_TYPE) { + v.aconst(Long.valueOf(increment)); + } + else if (asmType == Type.FLOAT_TYPE) { + v.aconst(Float.valueOf(increment)); + } + else if (asmType == Type.DOUBLE_TYPE) { + v.aconst(Double.valueOf(increment)); } else { - gen(operand, asmType); - if (asmType == Type.LONG_TYPE) { - v.aconst(Long.valueOf(increment)); - } - else if (asmType == Type.FLOAT_TYPE) { - v.aconst(Float.valueOf(increment)); - } - else if (asmType == Type.DOUBLE_TYPE) { - v.aconst(Double.valueOf(increment)); - } - else { - throw new UnsupportedOperationException("unknown type in increment: " + asmType); - } - v.add(asmType); - v.store(index, asmType); + v.aconst(increment); } - return index; + v.add(asmType); + value = generateIntermediateValue(operand); + value.store(v, true); + return value; } private void generateInv(Type asmType) { diff --git a/idea/src/org/jetbrains/jet/codegen/StackValue.java b/idea/src/org/jetbrains/jet/codegen/StackValue.java index b446773d0bb..1c1e2a0988e 100644 --- a/idea/src/org/jetbrains/jet/codegen/StackValue.java +++ b/idea/src/org/jetbrains/jet/codegen/StackValue.java @@ -19,7 +19,7 @@ public abstract class StackValue { public abstract void put(Type type, InstructionAdapter v); - public void store(InstructionAdapter v) { + public void store(InstructionAdapter v, boolean valueBeforeReceiver) { throw new UnsupportedOperationException("cannot store to value " + this); } @@ -160,7 +160,7 @@ public abstract class StackValue { } @Override - public void store(InstructionAdapter v) { + public void store(InstructionAdapter v, boolean valueBeforeReceiver) { v.store(index, this.type); } } @@ -328,7 +328,7 @@ public abstract class StackValue { } @Override - public void store(InstructionAdapter v) { + public void store(InstructionAdapter v, boolean valueBeforeReceiver) { v.astore(type); // assumes array and index are on the stack } } @@ -351,7 +351,11 @@ public abstract class StackValue { } @Override - public void store(InstructionAdapter v) { + public void store(InstructionAdapter v, boolean valueBeforeReceiver) { + // HACK should find some way to avoid this swap + if (valueBeforeReceiver && !isStatic) { + v.swap(); + } 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 6048dd482e6..3d3a38925c8 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -305,6 +305,21 @@ public class NamespaceGenTest extends CodegenTestCase { assertEquals(239, c.gridx); } + public void testFieldIncrement() throws Exception { + loadText("import java.awt.*; fun foo(c: GridBagConstraints) { c.gridx++; return; }"); + System.out.println(generateToText()); + final Method main = generateFunction(); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 609; + main.invoke(null, c); + assertEquals(610, c.gridx); + } + + public void testIncrementAsLastOperation() throws Exception { + loadText("fun foo() { var a = 0; a++; }"); + generateFunction(); // make sure we're not falling off end of code + } + public void testArrayRead() throws Exception { loadText("fun foo(c: Array) = c[0]"); final Method main = generateFunction();