From 686d4cae3c1c1d7818ec4f153d7e9a7a54a94194 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Fri, 27 Jan 2012 23:11:14 +0300 Subject: [PATCH] postfix part of KT-471 --- .../jet/codegen/ExpressionCodegen.java | 95 ++++++++++++++---- .../org/jetbrains/jet/codegen/StackValue.java | 32 ++++++ .../testData/codegen/regressions/kt471.kt | 97 +++++++++++++++++++ .../jetbrains/jet/codegen/ClassGenTest.java | 4 + 4 files changed, 211 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/codegen/regressions/kt471.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index c552c78b40d..fe741a40153 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2006,19 +2006,36 @@ public class ExpressionCodegen extends JetVisitor { Arrays.asList(expression.getBaseExpression()), receiver); } else { - return invokeOperation(expression, (FunctionDescriptor) op, (CallableMethod) callable); + DeclarationDescriptor cls = op.getContainingDeclaration(); + if (isNumberPrimitive(cls) || !(op.getName().equals("inc") || op.getName().equals("dec")) ) { + return invokeOperation(expression, (FunctionDescriptor) op, (CallableMethod) callable); + } + else { + ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference()); + assert resolvedCall != null; + + StackValue value = gen(expression.getBaseExpression()); + value.dupReceiver(v); + value.dupReceiver(v); + + Type type = expressionType(expression.getBaseExpression()); + value.put(type, v); + ((CallableMethod)callable).invoke(v); + value.store(v); + value.put(type, v); + return StackValue.onStack(type); + } } } private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) { ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference()); assert resolvedCall != null; - CallableMethod callableMethod = (CallableMethod) callable; - genThisAndReceiverFromResolvedCall(StackValue.none(), resolvedCall, callableMethod); + genThisAndReceiverFromResolvedCall(StackValue.none(), resolvedCall, callable); pushTypeArguments(resolvedCall); - pushMethodArguments(resolvedCall, callableMethod.getValueParameterTypes()); - callableMethod.invoke(v); - return returnValueAsStackValue((FunctionDescriptor) op, callableMethod.getSignature().getAsmMethod().getReturnType()); + pushMethodArguments(resolvedCall, callable.getValueParameterTypes()); + callable.invoke(v); + return returnValueAsStackValue(op, callable.getSignature().getAsmMethod().getReturnType()); } @Override @@ -2027,19 +2044,63 @@ public class ExpressionCodegen extends JetVisitor { if (op instanceof FunctionDescriptor) { final Type asmType = expressionType(expression); DeclarationDescriptor cls = op.getContainingDeclaration(); - if (isNumberPrimitive(cls) && (op.getName().equals("inc") || op.getName().equals("dec"))) { - receiver.put(receiver.type, v); - JetExpression operand = expression.getBaseExpression(); - if (operand instanceof JetReferenceExpression) { - final int index = indexOfLocal((JetReferenceExpression) operand); - if (index >= 0 && isIntPrimitive(asmType)) { - int increment = op.getName().equals("inc") ? 1 : -1; - return StackValue.postIncrement(index, increment); + if (op.getName().equals("inc") || op.getName().equals("dec")) { + if (isNumberPrimitive(cls)) { + receiver.put(receiver.type, v); + JetExpression operand = expression.getBaseExpression(); + if (operand instanceof JetReferenceExpression) { + final int index = indexOfLocal((JetReferenceExpression) operand); + if (index >= 0 && isIntPrimitive(asmType)) { + int increment = op.getName().equals("inc") ? 1 : -1; + return StackValue.postIncrement(index, increment); + } } + gen(operand, asmType); // old value + generateIncrement(op, asmType, operand, receiver); // increment in-place + return StackValue.onStack(asmType); // old value + } + else { + ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference()); + assert resolvedCall != null; + + final Callable callable = resolveToCallable(op, false); + + StackValue value = gen(expression.getBaseExpression()); + value.dupReceiver(v); + + Type type = expressionType(expression.getBaseExpression()); + value.put(type, v); + + switch(value.receiverSize()) { + case 0: + if(type.getSize() == 2) + v.dup2(); + else + v.dup(); + break; + + case 1: + if(type.getSize() == 2) + v.dup2X1(); + else + v.dupX1(); + break; + + case 2: + if(type.getSize() == 2) + v.dup2X2(); + else + v.dupX2(); + break; + + case -1: + throw new UnsupportedOperationException(); + } + + ((CallableMethod)callable).invoke(v); + value.store(v); + return StackValue.onStack(type); } - gen(operand, asmType); // old value - generateIncrement(op, asmType, operand, receiver); // increment in-place - return StackValue.onStack(asmType); // old value } } throw new UnsupportedOperationException("Don't know how to generate this prefix expression"); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 4a545bc89a4..cafee41d2cc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -51,6 +51,10 @@ public abstract class StackValue { public void dupReceiver(InstructionAdapter v) { } + public int receiverSize() { + return 0; + } + public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { if (this.type == Type.BOOLEAN_TYPE) { put(Type.BOOLEAN_TYPE, v); @@ -491,6 +495,10 @@ public abstract class StackValue { public void dupReceiver(InstructionAdapter v) { v.dup2(); // array and index } + + public int receiverSize() { + return 2; + } } private static class CollectionElement extends StackValue { @@ -547,6 +555,15 @@ public abstract class StackValue { ((IntrinsicMethod)setter).generate(codegen, v, null, null, null, null); } + public int receiverSize() { + if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) { + return 2; + } + else { + return -1; + } + } + @Override public void dupReceiver(InstructionAdapter v) { if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) { @@ -686,6 +703,9 @@ public abstract class StackValue { } private boolean isStandardStack(ResolvedCall call) { + if(call == null) + return true; + for (TypeParameterDescriptor typeParameterDescriptor : call.getResultingDescriptor().getTypeParameters()) { if(typeParameterDescriptor.isReified()) return false; @@ -736,6 +756,10 @@ public abstract class StackValue { } } + public int receiverSize() { + return isStatic ? 0 : 1; + } + @Override public void store(InstructionAdapter v) { v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor()); @@ -801,6 +825,10 @@ public abstract class StackValue { v.dup(); } } + + public int receiverSize() { + return isStatic ? 0 : 1; + } } private static class Expression extends StackValue { @@ -904,6 +932,10 @@ public abstract class StackValue { v.dup(); } + public int receiverSize() { + return 1; + } + @Override public void put(Type type, InstructionAdapter v) { Type sharedType = sharedTypeForType(this.type); diff --git a/compiler/testData/codegen/regressions/kt471.kt b/compiler/testData/codegen/regressions/kt471.kt new file mode 100644 index 00000000000..271cebf2d7c --- /dev/null +++ b/compiler/testData/codegen/regressions/kt471.kt @@ -0,0 +1,97 @@ +import java.util.ArrayList + +class MyNumber(val i: Int) { + fun inc(): MyNumber = MyNumber(i+1) +} + +class MNR(var ref: MyNumber) {} + +fun test1() : Boolean { + var m = MyNumber(42) + + m++ + if (m.i != 43) return false + return true +} + +fun test2() : Boolean { + var m = MyNumber(44) + + var m2 = m++ + if (m2.i != 44) return false + if (m.i != 45) return false + return true +} + +fun test3() : Boolean { + var mnr = MNR(MyNumber(42)) + mnr.ref++ + if (mnr.ref.i != 43) return false + return true +} + +fun test4() : Boolean { + var mnr = MNR(MyNumber(42)) + val m3 = mnr.ref++ + if (m3.i != 42) return false + return true +} + +fun test5() : Boolean { + var mnr = Array(2,{MyNumber(42)}) + mnr[0]++ + if (mnr[0].i != 43) return false + return true +} + +fun test6() : Boolean { + var mnr = Array(2,{it -> MyNumber(42-it)}) + mnr[1] = mnr[0]++ + if (mnr[0].i != 43) return false + if (mnr[1].i != 42) return false + return true +} + +/* +fun test7() : Boolean { + var mnr = ArrayList() + mnr.add(MyNumber(42)) + mnr[0]++ + if (mnr[0].i != 43) return false + return true +} + +fun test8() : Boolean { + var mnr = ArrayList() + mnr.add(MyNumber(42)) + mnr.add(MyNumber(41)) + mnr[1] = mnr[0]++ + if (mnr[0].i != 43) return false + if (mnr[1].i != 42) return false + return true +} +*/ + +fun box() : String { + var m = MyNumber(42) + + if (!test1()) return "fail test 1" + if (!test2()) return "fail test 2" + if (!test3()) return "fail test 3" + if (!test4()) return "fail test 4" + if (!test5()) return "fail test 5" + if (!test6()) return "fail test 6" +/* + if (!test7()) return "fail test 7" + if (!test8()) return "fail test 8" + + + ++m + if (m.i != 44) return "fail 0" + + var m1 = ++m + if (m1.i != 46) return "fail 3" + if (m.i != 46) return "fail 4" +*/ + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 5440347b3eb..39df82172b6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -261,4 +261,8 @@ public class ClassGenTest extends CodegenTestCase { public void testkt1157() throws Exception { blackBoxFile("regressions/kt1157.kt"); } + + public void testkt471() throws Exception { + blackBoxFile("regressions/kt471.kt"); + } }