From 58146c4452edda6959d4e5dda4534344c825a2c6 Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Tue, 15 Sep 2020 03:42:53 +0200 Subject: [PATCH] Keep DebugMetadata annotation when regenerate lambda with state-machine When a suspend lambda does not capture crossinline lambda, it is generated with as state-machine, since it does not inline anything. However, when regenerating, the inliner used to remove all DebugMetadata annotations to avoid duplication. This lead to missing annotation if the lambda is regenerated, but state-machine is not regenerated. This change fixes the blind spot by readding the annotation after regeneration. #KT-41789 Fixed --- .../inline/AnonymousObjectTransformer.kt | 21 +++++++++-- .../inline/coroutines/CoroutineTransformer.kt | 7 ++-- .../suspend/debugMetadataCrossinline.kt | 36 +++++++++++++++++++ .../BlackBoxInlineCodegenTestGenerated.java | 5 +++ ...otlinAgainstInlineKotlinTestGenerated.java | 5 +++ .../IrBlackBoxInlineCodegenTestGenerated.java | 5 +++ ...otlinAgainstInlineKotlinTestGenerated.java | 5 +++ ...JvmIrAgainstOldBoxInlineTestGenerated.java | 5 +++ ...JvmOldAgainstIrBoxInlineTestGenerated.java | 5 +++ 9 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt index 7b72275ddec..ea76cbff2c6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -57,6 +57,7 @@ class AnonymousObjectTransformer( lateinit var superClassName: String var sourceInfo: String? = null var debugInfo: String? = null + var debugMetadataAnnotation: AnnotationNode? = null createClassReader().accept(object : ClassVisitor(Opcodes.API_VERSION, classBuilder.visitor) { override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array) { @@ -77,7 +78,8 @@ class AnonymousObjectTransformer( val innerClassesInfo = FileBasedKotlinClass.InnerClassesInfo() return FileBasedKotlinClass.convertAnnotationVisitor(metadataReader, desc, innerClassesInfo) } else if (desc == DEBUG_METADATA_ANNOTATION_ASM_TYPE.descriptor) { - return null + debugMetadataAnnotation = AnnotationNode(desc) + return debugMetadataAnnotation } return super.visitAnnotation(desc, visible) } @@ -137,12 +139,20 @@ class AnonymousObjectTransformer( methodsToTransform, superClassName ) + var putDebugMetadata = false loop@ for (next in methodsToTransform) { val deferringVisitor = when { coroutineTransformer.shouldSkip(next) -> continue@loop coroutineTransformer.shouldGenerateStateMachine(next) -> coroutineTransformer.newMethod(next) - else -> newMethod(classBuilder, next) + else -> { + // Debug metadata is not put, but we should keep, since we do not generate state-machine, + // if the lambda does not capture crossinline lambdas. + if (coroutineTransformer.suspendLambdaWithGeneratedStateMachine(next)) { + putDebugMetadata = true + } + newMethod(classBuilder, next) + } } if (next.name == "") { @@ -190,6 +200,13 @@ class AnonymousObjectTransformer( writeTransformedMetadata(header, classBuilder) } + // debugMetadataAnnotation can be null in LV < 1.3 + if (putDebugMetadata && debugMetadataAnnotation != null) { + visitor.visitAnnotation(debugMetadataAnnotation!!.desc, true).also { + debugMetadataAnnotation!!.accept(it) + } + } + writeOuterInfo(visitor) if (inliningContext.generateAssertField && fieldNames.none { it.key == ASSERTIONS_DISABLED_FIELD_NAME }) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt index 708a865de45..c2c3e5b12cd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt @@ -43,11 +43,14 @@ class CoroutineTransformer( fun shouldGenerateStateMachine(node: MethodNode): Boolean { // Continuations are similar to lambdas from bird's view, but we should never generate state machine for them if (isContinuationNotLambda()) return false - // there can be suspend lambdas inside inline functions, which do not - // capture crossinline lambdas, thus, there is no need to transform them return isSuspendFunctionWithFakeConstructorCall(node) || (isSuspendLambda(node) && !isStateMachine(node)) } + // there can be suspend lambdas inside inline functions, which do not + // capture crossinline lambdas, thus, there is no need to transform them + fun suspendLambdaWithGeneratedStateMachine(node: MethodNode): Boolean = + !isContinuationNotLambda() && isSuspendLambda(node) && isStateMachine(node) + private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation && if (state.languageVersionSettings.isReleaseCoroutines()) superClassName.endsWith("ContinuationImpl") else methods.any { it.name == "getLabel" } diff --git a/compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt b/compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt new file mode 100644 index 00000000000..1abfca2af49 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt @@ -0,0 +1,36 @@ +// WITH_RUNTIME +// TARGET_BACKEND: JVM + +// FILE: inline.kt + +package test + +import kotlin.coroutines.* +import kotlin.coroutines.intrinsics.* + +fun runBlocking(c: suspend () -> Unit) { + c.startCoroutine(Continuation(EmptyCoroutineContext){}) +} + +inline fun foo(noinline block: (String) -> Unit) = runBlocking { + runCatching { + runBlocking { + var c: Continuation? = null + suspendCoroutineUninterceptedOrReturn { c = it; Unit } + block(c!!.toString()) + } + } + Unit +} + +// FILE: test.kt + +import test.* + +fun box(): String { + var res = "FAIL" + foo { + res = it + } + return if (res.contains(".invokeSuspend(inline.kt:")) "OK" else res +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index ff91b91b751..d4995cf85a8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -3818,6 +3818,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("debugMetadataCrossinline.kt") + public void testDebugMetadataCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt"); + } + @TestMetadata("delegatedProperties.kt") public void testDelegatedProperties_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines.experimental"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index fcab45b07eb..c9efac6fcbd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3818,6 +3818,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("debugMetadataCrossinline.kt") + public void testDebugMetadataCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt"); + } + @TestMetadata("delegatedProperties.kt") public void testDelegatedProperties_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines.experimental"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 45a0a700a51..9477afd7221 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -3808,6 +3808,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("debugMetadataCrossinline.kt") + public void testDebugMetadataCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt"); + } + @TestMetadata("delegatedProperties.kt") public void testDelegatedProperties_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 6d387a98518..dd8fb1ece1c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3808,6 +3808,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("debugMetadataCrossinline.kt") + public void testDebugMetadataCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt"); + } + @TestMetadata("delegatedProperties.kt") public void testDelegatedProperties_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxInlineTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxInlineTestGenerated.java index 8fdeb4c283f..84ed9fee1ec 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxInlineTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxInlineTestGenerated.java @@ -3808,6 +3808,11 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("debugMetadataCrossinline.kt") + public void testDebugMetadataCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt"); + } + @TestMetadata("delegatedProperties.kt") public void testDelegatedProperties_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxInlineTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxInlineTestGenerated.java index 6d5f10cff4c..1130c931085 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxInlineTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxInlineTestGenerated.java @@ -3808,6 +3808,11 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("debugMetadataCrossinline.kt") + public void testDebugMetadataCrossinline() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/debugMetadataCrossinline.kt"); + } + @TestMetadata("delegatedProperties.kt") public void testDelegatedProperties_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");