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
This commit is contained in:
+19
-2
@@ -57,6 +57,7 @@ class AnonymousObjectTransformer(
|
|||||||
lateinit var superClassName: String
|
lateinit var superClassName: String
|
||||||
var sourceInfo: String? = null
|
var sourceInfo: String? = null
|
||||||
var debugInfo: String? = null
|
var debugInfo: String? = null
|
||||||
|
var debugMetadataAnnotation: AnnotationNode? = null
|
||||||
|
|
||||||
createClassReader().accept(object : ClassVisitor(Opcodes.API_VERSION, classBuilder.visitor) {
|
createClassReader().accept(object : ClassVisitor(Opcodes.API_VERSION, classBuilder.visitor) {
|
||||||
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
|
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
|
||||||
@@ -77,7 +78,8 @@ class AnonymousObjectTransformer(
|
|||||||
val innerClassesInfo = FileBasedKotlinClass.InnerClassesInfo()
|
val innerClassesInfo = FileBasedKotlinClass.InnerClassesInfo()
|
||||||
return FileBasedKotlinClass.convertAnnotationVisitor(metadataReader, desc, innerClassesInfo)
|
return FileBasedKotlinClass.convertAnnotationVisitor(metadataReader, desc, innerClassesInfo)
|
||||||
} else if (desc == DEBUG_METADATA_ANNOTATION_ASM_TYPE.descriptor) {
|
} else if (desc == DEBUG_METADATA_ANNOTATION_ASM_TYPE.descriptor) {
|
||||||
return null
|
debugMetadataAnnotation = AnnotationNode(desc)
|
||||||
|
return debugMetadataAnnotation
|
||||||
}
|
}
|
||||||
return super.visitAnnotation(desc, visible)
|
return super.visitAnnotation(desc, visible)
|
||||||
}
|
}
|
||||||
@@ -137,12 +139,20 @@ class AnonymousObjectTransformer(
|
|||||||
methodsToTransform,
|
methodsToTransform,
|
||||||
superClassName
|
superClassName
|
||||||
)
|
)
|
||||||
|
var putDebugMetadata = false
|
||||||
loop@ for (next in methodsToTransform) {
|
loop@ for (next in methodsToTransform) {
|
||||||
val deferringVisitor =
|
val deferringVisitor =
|
||||||
when {
|
when {
|
||||||
coroutineTransformer.shouldSkip(next) -> continue@loop
|
coroutineTransformer.shouldSkip(next) -> continue@loop
|
||||||
coroutineTransformer.shouldGenerateStateMachine(next) -> coroutineTransformer.newMethod(next)
|
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 == "<clinit>") {
|
if (next.name == "<clinit>") {
|
||||||
@@ -190,6 +200,13 @@ class AnonymousObjectTransformer(
|
|||||||
writeTransformedMetadata(header, classBuilder)
|
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)
|
writeOuterInfo(visitor)
|
||||||
|
|
||||||
if (inliningContext.generateAssertField && fieldNames.none { it.key == ASSERTIONS_DISABLED_FIELD_NAME }) {
|
if (inliningContext.generateAssertField && fieldNames.none { it.key == ASSERTIONS_DISABLED_FIELD_NAME }) {
|
||||||
|
|||||||
+5
-2
@@ -43,11 +43,14 @@ class CoroutineTransformer(
|
|||||||
fun shouldGenerateStateMachine(node: MethodNode): Boolean {
|
fun shouldGenerateStateMachine(node: MethodNode): Boolean {
|
||||||
// Continuations are similar to lambdas from bird's view, but we should never generate state machine for them
|
// Continuations are similar to lambdas from bird's view, but we should never generate state machine for them
|
||||||
if (isContinuationNotLambda()) return false
|
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))
|
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 &&
|
private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation &&
|
||||||
if (state.languageVersionSettings.isReleaseCoroutines()) superClassName.endsWith("ContinuationImpl")
|
if (state.languageVersionSettings.isReleaseCoroutines()) superClassName.endsWith("ContinuationImpl")
|
||||||
else methods.any { it.name == "getLabel" }
|
else methods.any { it.name == "getLabel" }
|
||||||
|
|||||||
@@ -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 <reified E> foo(noinline block: (String) -> Unit) = runBlocking {
|
||||||
|
runCatching {
|
||||||
|
runBlocking {
|
||||||
|
var c: Continuation<Unit>? = null
|
||||||
|
suspendCoroutineUninterceptedOrReturn<Unit> { c = it; Unit }
|
||||||
|
block(c!!.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var res = "FAIL"
|
||||||
|
foo<Exception> {
|
||||||
|
res = it
|
||||||
|
}
|
||||||
|
return if (res.contains(".invokeSuspend(inline.kt:")) "OK" else res
|
||||||
|
}
|
||||||
+5
@@ -3818,6 +3818,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("delegatedProperties.kt")
|
||||||
public void testDelegatedProperties_1_2() throws Exception {
|
public void testDelegatedProperties_1_2() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines.experimental");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines.experimental");
|
||||||
|
|||||||
Generated
+5
@@ -3818,6 +3818,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("delegatedProperties.kt")
|
||||||
public void testDelegatedProperties_1_2() throws Exception {
|
public void testDelegatedProperties_1_2() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines.experimental");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines.experimental");
|
||||||
|
|||||||
+5
@@ -3808,6 +3808,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("delegatedProperties.kt")
|
||||||
public void testDelegatedProperties_1_3() throws Exception {
|
public void testDelegatedProperties_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
|
||||||
|
|||||||
Generated
+5
@@ -3808,6 +3808,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("delegatedProperties.kt")
|
||||||
public void testDelegatedProperties_1_3() throws Exception {
|
public void testDelegatedProperties_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
|
||||||
|
|||||||
+5
@@ -3808,6 +3808,11 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("delegatedProperties.kt")
|
||||||
public void testDelegatedProperties_1_3() throws Exception {
|
public void testDelegatedProperties_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
|
||||||
|
|||||||
+5
@@ -3808,6 +3808,11 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
|
|||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines");
|
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")
|
@TestMetadata("delegatedProperties.kt")
|
||||||
public void testDelegatedProperties_1_3() throws Exception {
|
public void testDelegatedProperties_1_3() throws Exception {
|
||||||
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
|
runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/delegatedProperties.kt", "kotlin.coroutines");
|
||||||
|
|||||||
Reference in New Issue
Block a user