diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/RedundantLocalsEliminationMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/RedundantLocalsEliminationMethodTransformer.kt index dcd4a75772a..67e880ecfd6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/RedundantLocalsEliminationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/RedundantLocalsEliminationMethodTransformer.kt @@ -122,7 +122,7 @@ class RedundantLocalsEliminationMethodTransformer : MethodTransformer() { val succ = findImmediateSuccessors(insn, cfg, methodNode).singleOrNull() ?: continue if (succ.opcode != Opcodes.POP) continue if (insn.opcode == Opcodes.ALOAD && methodNode.localVariables.firstOrNull { it.index == insn.localIndex() } != null) continue - val sources = findSourceInstructions(internalClassName, methodNode, listOf(succ)).values.flatten() + val sources = findSourceInstructions(internalClassName, methodNode, listOf(succ), ignoreCopy = false).values.flatten() if (sources.size != 1) continue res[insn] = succ } @@ -182,7 +182,7 @@ class RedundantLocalsEliminationMethodTransformer : MethodTransformer() { it.opcode == Opcodes.ASTORE && it.localIndex() == succ.localIndex() } != 1) continue if (!ignoreLocalVariableTable && methodNode.localVariables.firstOrNull { it.index == succ.localIndex() } != null) continue - val sources = findSourceInstructions(internalClassName, methodNode, listOf(succ)).values.flatten() + val sources = findSourceInstructions(internalClassName, methodNode, listOf(succ), ignoreCopy = false).values.flatten() if (sources.size > 1) continue res[insn] = succ } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/ReturnUnitMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/ReturnUnitMethodTransformer.kt index 853f488bac7..e67ab440f31 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/ReturnUnitMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/ReturnUnitMethodTransformer.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.sure import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.* +import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter /* * Replace POP with ARETURN iff @@ -47,7 +48,7 @@ object ReturnUnitMethodTransformer : MethodTransformer() { val pops = methodNode.instructions.asSequence().filter { it.opcode == Opcodes.POP }.toList() val popSuccessors = findSuccessors(methodNode, pops) - val sourceInsns = findSourceInstructions(internalClassName, methodNode, pops) + val sourceInsns = findSourceInstructions(internalClassName, methodNode, pops, ignoreCopy = true) val safePops = filterOutUnsafes(popSuccessors, units, sourceInsns) // Replace POP with ARETURN for tail call optimization @@ -122,9 +123,14 @@ object ReturnUnitMethodTransformer : MethodTransformer() { internal fun findSourceInstructions( internalClassName: String, methodNode: MethodNode, - insns: Collection + insns: Collection, + ignoreCopy: Boolean ): Map> { - val frames = MethodTransformer.analyze(internalClassName, methodNode, IgnoringCopyOperationSourceInterpreter()) + val frames = MethodTransformer.analyze( + internalClassName, + methodNode, + if (ignoreCopy) IgnoringCopyOperationSourceInterpreter() else SourceInterpreter() + ) return insns.keysToMap { val index = methodNode.instructions.indexOf(it) if (isUnreachable(index, frames)) return@keysToMap emptySet() diff --git a/compiler/testData/codegen/box/coroutines/redundantLocalsElimination/ktor_receivedMessage.kt b/compiler/testData/codegen/box/coroutines/redundantLocalsElimination/ktor_receivedMessage.kt new file mode 100644 index 00000000000..9078837334c --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/redundantLocalsElimination/ktor_receivedMessage.kt @@ -0,0 +1,43 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* + +private var prevSender: String = "FAIL" + +class ChatServer { + suspend fun who(sender: String) { + prevSender = sender + } + suspend fun sendTo(recipient: String, sender: String, message: String) { } + suspend fun message(sender: String, message: String) { } +} + +private val server = ChatServer() + +private suspend fun receivedMessage(id: String, command: String) { + when { + command.startsWith("/who") -> server.who(id) + command.startsWith("/user") -> { + val newName = command.removePrefix("/user").trim() + when { + newName.isEmpty() -> server.sendTo(id, "server::help", "/user [newName]") + else -> server.message(id, newName) + } + } + command.startsWith("/") -> server.sendTo(id, "server::help", "Unknown command ${command.takeWhile { !it.isWhitespace() }}") + else -> server.message(id, command) + } +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + builder { + receivedMessage("OK", "/who") + } + return prevSender +} \ 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 322237e821b..9688f504ff5 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 @@ -6514,6 +6514,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @TestMetadata("compiler/testData/codegen/box/coroutines/redundantLocalsElimination") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RedundantLocalsElimination extends AbstractIrBlackBoxCodegenTest { + public void testAllFilesPresentInRedundantLocalsElimination() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/redundantLocalsElimination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("ktor_receivedMessage.kt") + public void testKtor_receivedMessage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/redundantLocalsElimination/ktor_receivedMessage.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 459169b67d2..94eaac6eab1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -6514,6 +6514,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/coroutines/redundantLocalsElimination") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RedundantLocalsElimination extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInRedundantLocalsElimination() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/redundantLocalsElimination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("ktor_receivedMessage.kt") + public void testKtor_receivedMessage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/redundantLocalsElimination/ktor_receivedMessage.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 01c992c6057..f8938d81ee0 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -6514,6 +6514,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/coroutines/redundantLocalsElimination") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RedundantLocalsElimination extends AbstractLightAnalysisModeTest { + public void testAllFilesPresentInRedundantLocalsElimination() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/redundantLocalsElimination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("ktor_receivedMessage.kt") + public void testKtor_receivedMessage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/redundantLocalsElimination/ktor_receivedMessage.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) 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 56526f48684..40afccadeab 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 @@ -7810,6 +7810,21 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/coroutines/redundantLocalsElimination") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RedundantLocalsElimination extends AbstractJsCodegenBoxTest { + public void testAllFilesPresentInRedundantLocalsElimination() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/redundantLocalsElimination"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("ktor_receivedMessage.kt") + public void testKtor_receivedMessage() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/redundantLocalsElimination/ktor_receivedMessage.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/stackUnwinding") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)