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 8c480c81ef7..1d5ea660159 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 @@ -58,16 +58,9 @@ internal class FixStackAnalyzer( for (marker in context.fakeAlwaysFalseIfeqMarkers) { val next = marker.next if (next is JumpInsnNode) { - val nop = InsnNode(Opcodes.NOP) - expectedStackNode[next.label] = nop - method.instructions.insert(next, nop) - method.instructions.remove(marker) - method.instructions.remove(next) - context.nodesToRemoveOnCleanup.add(nop) + expectedStackNode[next.label] = marker } } - - context.fakeAlwaysFalseIfeqMarkers.clear() } private val analyzer = InternalAnalyzer(owner, method, context) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackContext.kt index 31b414f4919..71986dbadde 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackContext.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackContext.kt @@ -39,8 +39,6 @@ internal class FixStackContext(val methodNode: MethodNode) { val openingInlineMethodMarker = hashMapOf() var consistentInlineMarkers: Boolean = true; private set - val nodesToRemoveOnCleanup = arrayListOf() - init { saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode) isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty() diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackMethodTransformer.kt index ddbb1a724e3..594f1817e64 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackMethodTransformer.kt @@ -39,31 +39,51 @@ class FixStackMethodTransformer : MethodTransformer() { } if (context.isAnalysisRequired()) { - val analyzer = FixStackAnalyzer(internalClassName, methodNode, context) - analyzer.analyze() - - methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize - - val actions = arrayListOf<() -> Unit>() - - transformBreakContinueGotos(methodNode, context, actions, analyzer) - - transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer) - - actions.forEach { it() } + analyzeAndTransformBreakContinueGotos(context, internalClassName, methodNode) + removeAlwaysFalseIfeqMarkers(context, methodNode) + analyzeAndTransformSaveRestoreStack(context, internalClassName, methodNode) } - context.fakeAlwaysTrueIfeqMarkers.forEach { marker -> - replaceAlwaysTrueIfeqWithGoto(methodNode, marker) - } + removeAlwaysTrueIfeqMarkers(context, methodNode) + removeAlwaysFalseIfeqMarkers(context, methodNode) + } + private fun analyzeAndTransformBreakContinueGotos(context: FixStackContext, internalClassName: String, methodNode: MethodNode) { + val analyzer = FixStackAnalyzer(internalClassName, methodNode, context) + analyzer.analyze() + + methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize + + val actions = arrayListOf<() -> Unit>() + + transformBreakContinueGotos(methodNode, context, actions, analyzer) + + actions.forEach { it() } + } + + private fun analyzeAndTransformSaveRestoreStack(context: FixStackContext, internalClassName: String, methodNode: MethodNode) { + val analyzer = FixStackAnalyzer(internalClassName, methodNode, context) + analyzer.analyze() + + val actions = arrayListOf<() -> Unit>() + + transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer) + + actions.forEach { it() } + } + + private fun removeAlwaysFalseIfeqMarkers(context: FixStackContext, methodNode: MethodNode) { context.fakeAlwaysFalseIfeqMarkers.forEach { marker -> removeAlwaysFalseIfeq(methodNode, marker) } + context.fakeAlwaysFalseIfeqMarkers.clear() + } - context.nodesToRemoveOnCleanup.forEach { - methodNode.instructions.remove(it) + private fun removeAlwaysTrueIfeqMarkers(context: FixStackContext, methodNode: MethodNode) { + context.fakeAlwaysTrueIfeqMarkers.forEach { marker -> + replaceAlwaysTrueIfeqWithGoto(methodNode, marker) } + context.fakeAlwaysTrueIfeqMarkers.clear() } private fun transformBreakContinueGotos( diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt new file mode 100644 index 00000000000..91199580064 --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt @@ -0,0 +1,30 @@ +class MyQueue { + fun poll(): String? = null +} + +class A { + val delayedQueue = MyQueue() + + fun next() { + while (true) { + delayedQueue.poll() ?: break + } + + while (true) { + unblock(delayedQueue.poll() ?: break) + } + + while (true) { + unblock(delayedQueue.poll() ?: break) + } + } + + fun unblock(p: String) { + + } +} + +fun box() : String { + A().next() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.kt b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.kt new file mode 100644 index 00000000000..17a4079833e --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.kt @@ -0,0 +1,32 @@ +class MyQueue { + fun poll(): String? = null +} + +class A { + val delayedQueue = MyQueue() + + var cond = true + + fun next() { + while (cond) { + delayedQueue.poll() ?: break + } + + while (cond) { + unblock(delayedQueue.poll() ?: break) + } + + while (cond) { + unblock(delayedQueue.poll() ?: break) + } + } + + fun unblock(p: String) { + + } +} + +fun box() : String { + A().next() + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/light-analysis/controlStructures/breakContinueInExpressions/kt16713.txt b/compiler/testData/codegen/light-analysis/controlStructures/breakContinueInExpressions/kt16713.txt new file mode 100644 index 00000000000..732ef0f2287 --- /dev/null +++ b/compiler/testData/codegen/light-analysis/controlStructures/breakContinueInExpressions/kt16713.txt @@ -0,0 +1,19 @@ +@kotlin.Metadata +public final class A { + private final @org.jetbrains.annotations.NotNull field delayedQueue: MyQueue + public method (): void + public final @org.jetbrains.annotations.NotNull method getDelayedQueue(): MyQueue + public final method next(): void + public final method unblock(@org.jetbrains.annotations.NotNull p0: java.lang.String): void +} + +@kotlin.Metadata +public final class Kt16713Kt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +@kotlin.Metadata +public final class MyQueue { + public method (): void + public final @org.jetbrains.annotations.Nullable method poll(): java.lang.String +} diff --git a/compiler/testData/codegen/light-analysis/controlStructures/breakContinueInExpressions/kt16713_2.txt b/compiler/testData/codegen/light-analysis/controlStructures/breakContinueInExpressions/kt16713_2.txt new file mode 100644 index 00000000000..a16afe6c5c1 --- /dev/null +++ b/compiler/testData/codegen/light-analysis/controlStructures/breakContinueInExpressions/kt16713_2.txt @@ -0,0 +1,22 @@ +@kotlin.Metadata +public final class A { + private field cond: boolean + private final @org.jetbrains.annotations.NotNull field delayedQueue: MyQueue + public method (): void + public final method getCond(): boolean + public final @org.jetbrains.annotations.NotNull method getDelayedQueue(): MyQueue + public final method next(): void + public final method setCond(p0: boolean): void + public final method unblock(@org.jetbrains.annotations.NotNull p0: java.lang.String): void +} + +@kotlin.Metadata +public final class Kt16713_2Kt { + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} + +@kotlin.Metadata +public final class MyQueue { + public method (): void + public final @org.jetbrains.annotations.Nullable method poll(): java.lang.String +} 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 ec3c55890a2..97fed2a00fb 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 @@ -4456,6 +4456,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("kt16713.kt") + public void testKt16713() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt"); + doTest(fileName); + } + + @TestMetadata("kt16713_2.kt") + public void testKt16713_2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.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 f68d573f33a..84d4946de1c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4456,6 +4456,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt16713.kt") + public void testKt16713() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt"); + doTest(fileName); + } + + @TestMetadata("kt16713_2.kt") + public void testKt16713_2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.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 7cf65c33b2b..9a438eca61d 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 @@ -5153,6 +5153,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("kt16713.kt") + public void testKt16713() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713.kt"); + doTest(fileName); + } + + @TestMetadata("kt16713_2.kt") + public void testKt16713_2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt16713_2.kt"); + doTest(fileName); + } + @TestMetadata("kt9022And.kt") public void testKt9022And() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");