From becb1f1f957f25e9625506f0635620342c84dbf3 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 25 Jul 2016 11:50:35 +0300 Subject: [PATCH] Make stack values for assignment-like operations lazy As well as for other kinds of expressions Within attached test they were generated twice in case of last expression of coroutine block, because coroutine related codegen part is built upon assumption that all expressions should be generated lazily Also add a test about unary postfix increment/decrement #KT-13156 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 45 ++++++++++++------- .../box/coroutines/lastStatementInc.kt | 43 ++++++++++++++++++ .../box/coroutines/lastStementAssignment.kt | 45 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 12 +++++ 4 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/lastStatementInc.kt create mode 100644 compiler/testData/codegen/box/coroutines/lastStementAssignment.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 88957894c26..bd815051aa4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -3590,30 +3590,41 @@ public class ExpressionCodegen extends KtVisitor impleme return StackValue.cmp(expression.getOperationToken(), type, leftValue, rightValue); } - private StackValue generateAssignmentExpression(KtBinaryExpression expression) { - StackValue stackValue = gen(expression.getLeft()); - KtExpression right = expression.getRight(); - assert right != null : expression.getText(); - stackValue.store(gen(right), v); - return StackValue.none(); + private StackValue generateAssignmentExpression(final KtBinaryExpression expression) { + return StackValue.operation(Type.VOID_TYPE, new Function1() { + @Override + public Unit invoke(InstructionAdapter adapter) { + StackValue stackValue = gen(expression.getLeft()); + KtExpression right = expression.getRight(); + assert right != null : expression.getText(); + stackValue.store(gen(right), v); + + return Unit.INSTANCE; + } + }); } - private StackValue generateAugmentedAssignment(KtBinaryExpression expression) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); - FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall); - Callable callable = resolveToCallable(descriptor, false, resolvedCall); - KtExpression lhs = expression.getLeft(); - Type lhsType = expressionType(lhs); + private StackValue generateAugmentedAssignment(final KtBinaryExpression expression) { + return StackValue.operation(Type.VOID_TYPE, new Function1() { + @Override + public Unit invoke(InstructionAdapter adapter) { + ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext); + FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall); + Callable callable = resolveToCallable(descriptor, false, resolvedCall); + KtExpression lhs = expression.getLeft(); + Type lhsType = expressionType(lhs); - boolean keepReturnValue = Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression)) - || !KotlinBuiltIns.isUnit(descriptor.getReturnType()); + boolean keepReturnValue = Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression)) + || !KotlinBuiltIns.isUnit(descriptor.getReturnType()); - callAugAssignMethod(expression, resolvedCall, callable, lhsType, keepReturnValue); + putCallAugAssignMethod(expression, resolvedCall, callable, lhsType, keepReturnValue); - return StackValue.none(); + return Unit.INSTANCE; + } + }); } - private void callAugAssignMethod( + private void putCallAugAssignMethod( @NotNull KtBinaryExpression expression, @NotNull ResolvedCall resolvedCall, @NotNull Callable callable, diff --git a/compiler/testData/codegen/box/coroutines/lastStatementInc.kt b/compiler/testData/codegen/box/coroutines/lastStatementInc.kt new file mode 100644 index 00000000000..be98bbc480d --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/lastStatementInc.kt @@ -0,0 +1,43 @@ +class Controller { + var wasHandleResultCalled = false + suspend fun suspendHere(x: Continuation) { + x.resume("OK") + } + + operator fun handleResult(x: Unit, y: Continuation) { + wasHandleResultCalled = true + } +} + +fun builder(coroutine c: Controller.() -> Continuation) { + val controller = Controller() + c(controller).resume(Unit) + + if (!controller.wasHandleResultCalled) throw java.lang.RuntimeException("fail 1") +} + +fun box(): String { + var result = 0 + + builder { + result++ + + if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 2") + + result-- + } + + if (result != 0) return "fail 3" + + builder { + --result + + if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 4") + + ++result + } + + if (result != 0) return "fail 5" + + return "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/lastStementAssignment.kt b/compiler/testData/codegen/box/coroutines/lastStementAssignment.kt new file mode 100644 index 00000000000..75e0f914a12 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/lastStementAssignment.kt @@ -0,0 +1,45 @@ +class Controller { + var wasHandleResultCalled = false + suspend fun suspendHere(x: Continuation) { + x.resume("OK") + } + + operator fun handleResult(x: Unit, y: Continuation) { + wasHandleResultCalled = true + } +} + +fun builder(coroutine c: Controller.() -> Continuation) { + val controller = Controller() + c(controller).resume(Unit) + + if (!controller.wasHandleResultCalled) throw java.lang.RuntimeException("fail 1") +} + +var varWithCustomSetter: String = "" + set(value) { + if (field != "") throw java.lang.RuntimeException("fail 2") + field = value + } + +fun box(): String { + var result = "" + + builder { + result += "O" + + if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 3") + + result += "K" + } + + if (result != "OK") return "fail 4" + + builder { + if (suspendHere() != "OK") throw java.lang.RuntimeException("fail 5") + + varWithCustomSetter = "OK" + } + + return varWithCustomSetter +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index b7ac3f19377..6fb20c3bb1a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4285,6 +4285,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("lastStatementInc.kt") + public void testLastStatementInc() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastStatementInc.kt"); + doTest(fileName); + } + + @TestMetadata("lastStementAssignment.kt") + public void testLastStementAssignment() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastStementAssignment.kt"); + doTest(fileName); + } + @TestMetadata("lastUnitExpression.kt") public void testLastUnitExpression() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastUnitExpression.kt");