From b429f7bc86857b27e53de628efdf5ab4f6bafaf8 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 10 Nov 2016 18:09:32 +0300 Subject: [PATCH] KT-14581 Make FixStackAnalyzer tolerant to uninitialized values --- .../common/OptimizationBasicInterpreter.java | 14 +++++++++-- .../optimization/fixStack/FixStackAnalyzer.kt | 2 +- .../fixStack/LocalVariablesManager.kt | 4 ++++ .../breakInDoWhile.kt | 10 ++++++++ .../continueInDoWhile.kt | 6 +++++ .../breakContinueInExpressions/kt14581.kt | 11 +++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 18 ++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 18 ++++++++++++++ .../semantics/JsCodegenBoxTestGenerated.java | 24 +++++++++++++++++++ 9 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt create mode 100644 compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt create mode 100644 compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java index 1b8569d2e9e..640bf95cdbb 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java @@ -31,9 +31,15 @@ import java.util.List; import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*; public class OptimizationBasicInterpreter extends Interpreter implements Opcodes { + private final boolean tolerantToUninitializedValues; + + public OptimizationBasicInterpreter(boolean tolerantToUninitializedValues) { + super(ASM5); + this.tolerantToUninitializedValues = tolerantToUninitializedValues; + } public OptimizationBasicInterpreter() { - super(ASM5); + this(false); } @Override @@ -355,7 +361,11 @@ public class OptimizationBasicInterpreter extends Interpreter implem ) { if (v.equals(w)) return v; - if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) { + if (tolerantToUninitializedValues) { + if (v == StrictBasicValue.UNINITIALIZED_VALUE) return w; + if (w == StrictBasicValue.UNINITIALIZED_VALUE) return v; + } + else if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) { return StrictBasicValue.UNINITIALIZED_VALUE; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt index 48d5bd7bd43..deaa0ec6fa6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt @@ -33,7 +33,7 @@ internal class FixStackAnalyzer( owner: String, methodNode: MethodNode, val context: FixStackContext -) : MethodAnalyzer(owner, methodNode, OptimizationBasicInterpreter()) { +) : MethodAnalyzer(owner, methodNode, OptimizationBasicInterpreter(/* tolerantToUninitializedValues = */true)) { val savedStacks = hashMapOf>() var maxExtraStackSize = 0; private set diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/LocalVariablesManager.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/LocalVariablesManager.kt index f748c536469..ab7dbb1b8d6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/LocalVariablesManager.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/LocalVariablesManager.kt @@ -44,6 +44,10 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod } private fun allocateNewHandle(numRestoreStackMarkers: Int, saveStackMarker: AbstractInsnNode, savedStackValues: List): SavedStackDescriptor { + if (savedStackValues.any { it.type == null }) { + throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}") + } + val firstUnusedLocalVarIndex = getFirstUnusedLocalVariableIndex() val savedStackDescriptor = SavedStackDescriptor(savedStackValues, firstUnusedLocalVarIndex) updateMaxLocals(savedStackDescriptor.firstUnusedLocalVarIndex) diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt new file mode 100644 index 00000000000..cd932454965 --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt @@ -0,0 +1,10 @@ +fun box(): String { + val ok: String? = "OK" + var res = "" + + do { + res += ok ?: break + } while (false) + + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt new file mode 100644 index 00000000000..d46fe01fd97 --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt @@ -0,0 +1,6 @@ +fun box(): String { + var i = 0 + do continue while (i++ < 3) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt new file mode 100644 index 00000000000..0010f1ffdbd --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt @@ -0,0 +1,11 @@ +fun foo(x: String): String { + var y: String + do { + y = x + } while (y != x.bar(x)) + return y +} + +inline fun String.bar(other: String) = this + +fun box(): String = foo("OK") \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index e28de189b5a..1ad297b8180 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -4156,12 +4156,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("breakInDoWhile.kt") + public void testBreakInDoWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt"); + doTest(fileName); + } + @TestMetadata("breakInExpr.kt") public void testBreakInExpr() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInExpr.kt"); doTest(fileName); } + @TestMetadata("continueInDoWhile.kt") + public void testContinueInDoWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt"); + doTest(fileName); + } + @TestMetadata("continueInExpr.kt") public void testContinueInExpr() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInExpr.kt"); @@ -4180,6 +4192,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("kt14581.kt") + public void testKt14581() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt"); + doTest(fileName); + } + @TestMetadata("kt9022And.kt") public void testKt9022And() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 78a5ee86205..c6090c342a4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4156,12 +4156,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("breakInDoWhile.kt") + public void testBreakInDoWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt"); + doTest(fileName); + } + @TestMetadata("breakInExpr.kt") public void testBreakInExpr() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInExpr.kt"); doTest(fileName); } + @TestMetadata("continueInDoWhile.kt") + public void testContinueInDoWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt"); + doTest(fileName); + } + @TestMetadata("continueInExpr.kt") public void testContinueInExpr() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInExpr.kt"); @@ -4180,6 +4192,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt14581.kt") + public void testKt14581() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt"); + doTest(fileName); + } + @TestMetadata("kt9022And.kt") public void testKt9022And() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 34fa0ddf8fa..5ca903e57d4 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -5140,12 +5140,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @TestMetadata("breakInDoWhile.kt") + public void testBreakInDoWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInDoWhile.kt"); + doTest(fileName); + } + @TestMetadata("breakInExpr.kt") public void testBreakInExpr() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/breakInExpr.kt"); doTest(fileName); } + @TestMetadata("continueInDoWhile.kt") + public void testContinueInDoWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInDoWhile.kt"); + doTest(fileName); + } + @TestMetadata("continueInExpr.kt") public void testContinueInExpr() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/continueInExpr.kt"); @@ -5164,6 +5176,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("kt14581.kt") + public void testKt14581() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt14581.kt"); + doTest(fileName); + } + @TestMetadata("kt9022And.kt") public void testKt9022And() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt"); @@ -7088,6 +7106,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("kt13557.kt") + public void testKt13557() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/kt13557.kt"); + doTest(fileName); + } + @TestMetadata("localVal.kt") public void testLocalVal() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/localVal.kt");