diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index 0eb01394e52..c8364e88a5b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -692,6 +692,14 @@ private fun allSuspensionPointsAreTailCalls( val beginIndex = instructions.indexOf(suspensionPoint.suspensionCallBegin) val endIndex = instructions.indexOf(suspensionPoint.suspensionCallEnd) + val insideTryBlock = methodNode.tryCatchBlocks.any { block -> + val tryBlockStartIndex = instructions.indexOf(block.start) + val tryBlockEndIndex = instructions.indexOf(block.end) + + beginIndex in tryBlockStartIndex..tryBlockEndIndex + } + if (insideTryBlock) return@all false + safelyReachableReturns[endIndex + 1]?.all { returnIndex -> val sourceInsn = sourceFrames[returnIndex].top().sure { diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt new file mode 100644 index 00000000000..8207febcf58 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt @@ -0,0 +1,37 @@ +// WITH_RUNTIME +// WITH_COROUTINES +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +val postponedActions = ArrayList<() -> Unit>() + +suspend fun suspendWithException(): String = suspendCoroutine { x -> + postponedActions.add { + x.resumeWithException(Exception("OK")) + } +} + +suspend fun catchException(): String { + try { + return suspendWithException() + } + catch(e: Exception) { + return e.message!! + } +} + +fun run(c: suspend () -> String): String { + var res: String = "FAIL 0" + c.startCoroutine(handleResultContinuation { + res = it + }) + postponedActions[0]() + return res +} + +fun box(): String { + return run { + catchException() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/tryCatchTailCall.kt b/compiler/testData/codegen/bytecodeListing/tryCatchTailCall.kt new file mode 100644 index 00000000000..d4e43c52164 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/tryCatchTailCall.kt @@ -0,0 +1,10 @@ +suspend fun catchException(): String { + try { + return suspendWithException() + } + catch(e: Exception) { + return e.message!! + } +} + +suspend fun suspendWithException(): String = TODO() diff --git a/compiler/testData/codegen/bytecodeListing/tryCatchTailCall.txt b/compiler/testData/codegen/bytecodeListing/tryCatchTailCall.txt new file mode 100644 index 00000000000..1460a54f81f --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/tryCatchTailCall.txt @@ -0,0 +1,17 @@ +@kotlin.Metadata +final class TryCatchTailCallKt$catchException$1 { + synthetic field data: java.lang.Object + synthetic field exception: java.lang.Throwable + inner class TryCatchTailCallKt$catchException$1 + method (p0: kotlin.coroutines.experimental.Continuation): void + public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object + synthetic final method getLabel(): int + synthetic final method setLabel(p0: int): void +} + +@kotlin.Metadata +public final class TryCatchTailCallKt { + inner class TryCatchTailCallKt$catchException$1 + public final static @org.jetbrains.annotations.Nullable method catchException(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method suspendWithException(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object +} 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 343e19c2f37..b3c0e0234d4 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 @@ -6388,6 +6388,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt"); doTest(fileName); } + + @TestMetadata("tryCatch.kt") + public void testTryCatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 22e422f9ab0..9df6d6323b6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -6388,6 +6388,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt"); doTest(fileName); } + + @TestMetadata("tryCatch.kt") + public void testTryCatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index f4f7af9a177..f3d8c381f3c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -157,6 +157,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { doTest(fileName); } + @TestMetadata("tryCatchTailCall.kt") + public void testTryCatchTailCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/tryCatchTailCall.kt"); + doTest(fileName); + } + @TestMetadata("compiler/testData/codegen/bytecodeListing/annotations") @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 cffee5439e8..2089d6a04a4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -6388,6 +6388,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt"); doTest(fileName); } + + @TestMetadata("tryCatch.kt") + public void testTryCatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations") 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 195b5cfbf1a..7c8748f5d2c 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 @@ -6946,6 +6946,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt"); doTest(fileName); } + + @TestMetadata("tryCatch.kt") + public void testTryCatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatch.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/box/coroutines/tailOperations")