From 4ca522bf0e4395a77765983da20b52d8444c1de5 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 4 Feb 2013 14:44:25 +0400 Subject: [PATCH] Fix codegen of do-while condition The condition of a do-while loop can use variables declared in the loop (variables can only be declared inside a block). Previously this behaviour caused crash because after the block was generated, all variables declared inside that block were gone from myFrameMap #KT-3280 Fixed --- .../jet/codegen/ExpressionCodegen.java | 35 +++++++++++++------ .../codegen/box/controlStructures/doWhile.kt | 15 ++++++++ .../box/controlStructures/doWhileFib.kt | 12 +++++++ .../codegen/box/controlStructures/kt3280.kt | 24 +++++++++++++ .../BlackBoxCodegenTestGenerated.java | 15 ++++++++ 5 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/codegen/box/controlStructures/doWhile.kt create mode 100644 compiler/testData/codegen/box/controlStructures/doWhileFib.kt create mode 100644 compiler/testData/codegen/box/controlStructures/kt3280.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index dbf51228975..1cebd321e1f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -55,7 +55,6 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmClassName; -import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType; import org.jetbrains.jet.lang.resolve.scopes.receivers.*; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; @@ -421,22 +420,38 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitDoWhileExpression(JetDoWhileExpression expression, StackValue receiver) { - Label condition = new Label(); - v.mark(condition); + Label continueLabel = new Label(); + v.mark(continueLabel); - Label end = new Label(); + Label breakLabel = new Label(); - blockStackElements.push(new LoopBlockStackElement(end, condition, targetLabel(expression))); + blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression))); - gen(expression.getBody(), Type.VOID_TYPE); + JetExpression body = expression.getBody(); + JetExpression condition = expression.getCondition(); + StackValue conditionValue; - final StackValue conditionValue = gen(expression.getCondition()); - conditionValue.condJump(condition, false, v); + if (body instanceof JetBlockExpression) { + // If body's a block, it can contain variable declarations which may be used in the condition of a do-while loop. + // We handle this case separately because otherwise such variable will be out of the frame map after the block ends + List doWhileStatements = ((JetBlockExpression) body).getStatements(); - v.mark(end); + List statements = new ArrayList(doWhileStatements.size() + 1); + statements.addAll(doWhileStatements); + statements.add(condition); + + conditionValue = generateBlock(statements, true); + } + else { + gen(body, Type.VOID_TYPE); + conditionValue = gen(condition); + } + + conditionValue.condJump(continueLabel, false, v); + v.mark(breakLabel); blockStackElements.pop(); - return StackValue.onStack(Type.VOID_TYPE); + return StackValue.none(); } @Override diff --git a/compiler/testData/codegen/box/controlStructures/doWhile.kt b/compiler/testData/codegen/box/controlStructures/doWhile.kt new file mode 100644 index 00000000000..f9b776c736c --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/doWhile.kt @@ -0,0 +1,15 @@ +fun box(): String { + var x = 0 + do x++ while (x < 5) + if (x != 5) return "Fail 1 $x" + + var y = 0 + do { y++ } while (y < 5) + if (y != 5) return "Fail 2 $y" + + var z = "" + do { z += z.length } while (z.length < 5) + if (z != "01234") return "Fail 3 $z" + + return "OK" +} diff --git a/compiler/testData/codegen/box/controlStructures/doWhileFib.kt b/compiler/testData/codegen/box/controlStructures/doWhileFib.kt new file mode 100644 index 00000000000..088f74cb660 --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/doWhileFib.kt @@ -0,0 +1,12 @@ +fun box(): String { + var fx = 1 + var fy = 1 + + do { + var tmp = fy + fy = fx + fy + fx = tmp + } while (fy < 100) + + return if (fy == 144) "OK" else "Fail $fx $fy" +} diff --git a/compiler/testData/codegen/box/controlStructures/kt3280.kt b/compiler/testData/codegen/box/controlStructures/kt3280.kt new file mode 100644 index 00000000000..2a2b87a8f1c --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/kt3280.kt @@ -0,0 +1,24 @@ +fun foo() { + var x = 0 + do { + x++ + var y = x + 5 + } while (y < 10) + if (x != 5) throw AssertionError("$x") +} + +fun bar() { + var b = false + do { + var x = "X" + var y = "Y" + b = true + } while (x + y != "XY") + if (!b) throw AssertionError() +} + +fun box(): String { + foo() + bar() + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 79a2fe432e3..f474b2273dc 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1012,6 +1012,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/continueToLabelInFor.kt"); } + @TestMetadata("doWhile.kt") + public void testDoWhile() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/doWhile.kt"); + } + + @TestMetadata("doWhileFib.kt") + public void testDoWhileFib() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/doWhileFib.kt"); + } + @TestMetadata("finallyOnEmptyReturn.kt") public void testFinallyOnEmptyReturn() throws Exception { blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/finallyOnEmptyReturn.kt"); @@ -1157,6 +1167,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt3273.kt"); } + @TestMetadata("kt3280.kt") + public void testKt3280() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt3280.kt"); + } + @TestMetadata("kt416.kt") public void testKt416() throws Exception { blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt416.kt");