diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt index 1be1a4745cb..ac1867d0917 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom import org.jetbrains.kotlin.backend.common.ir.copyValueParametersInsertingContinuationFrom import org.jetbrains.kotlin.backend.common.ir.isSuspend import org.jetbrains.kotlin.backend.common.lower.VariableRemapper +import org.jetbrains.kotlin.backend.common.lower.allOverridden import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.codegen.ClassBuilder @@ -71,8 +72,8 @@ internal fun generateStateMachineForNamedFunction( internalNameForDispatchReceiver = classCodegen.visitor.thisName, putContinuationParameterToLvt = false, disableTailCallOptimizationForFunctionReturningUnit = irFunction.returnType.isUnit() && - (irFunction as? IrSimpleFunction)?.overriddenSymbols?.let { symbols -> - symbols.isNotEmpty() && symbols.any { !it.owner.returnType.isUnit() } + (irFunction as? IrSimpleFunction)?.allOverridden()?.toList()?.let { functions -> + functions.isNotEmpty() && functions.any { !it.returnType.isUnit() } } == true ) } @@ -135,10 +136,10 @@ internal fun IrFunction.getOrCreateSuspendFunctionViewIfNeeded(context: JvmBacke if (!isSuspend || origin == JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW || origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW ) return this - return context.suspendFunctionOriginalToView[this] ?: suspendFunctionView(context) + return context.suspendFunctionOriginalToView[this] ?: suspendFunctionView(context, true) } -private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFunction { +fun IrFunction.suspendFunctionView(context: JvmBackendContext, generateBody: Boolean): IrFunction { require(this.isSuspend && this is IrSimpleFunction) // For SuspendFunction{N}.invoke we need to generate INVOKEINTERFACE Function{N+1}.invoke(...Ljava/lang/Object;)... // instead of INVOKEINTERFACE Function{N+1}.invoke(...Lkotlin/coroutines/Continuation;)... @@ -175,19 +176,21 @@ private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFuncti continuationValueParam = it.addValueParameter(SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME, continuationType) } - // Add the suspend function view to the map before transforming the body to make sure - // that recursive suspend functions do not lead to unbounded recursion at compile time. - context.recordSuspendFunctionView(this, it) + if (generateBody) { + // Add the suspend function view to the map before transforming the body to make sure + // that recursive suspend functions do not lead to unbounded recursion at compile time. + context.recordSuspendFunctionView(this, it) - val valueParametersMapping = explicitParameters.zip(it.explicitParameters.filter { it != continuationValueParam }).toMap() - it.body = body?.deepCopyWithSymbols(this) - it.body?.transformChildrenVoid(object : VariableRemapper(valueParametersMapping) { - // Do not cross class boundaries inside functions. Otherwise, callable references will try to access wrong $completion. - override fun visitClass(declaration: IrClass): IrStatement = declaration + val valueParametersMapping = explicitParameters.zip(it.explicitParameters.filter { it != continuationValueParam }).toMap() + it.body = body?.deepCopyWithSymbols(this) + it.body?.transformChildrenVoid(object : VariableRemapper(valueParametersMapping) { + // Do not cross class boundaries inside functions. Otherwise, callable references will try to access wrong $completion. + override fun visitClass(declaration: IrClass): IrStatement = declaration - override fun visitCall(expression: IrCall): IrExpression = - super.visitCall(expression.createSuspendFunctionCallViewIfNeeded(context, it, callerIsInlineLambda = false)) - }) + override fun visitCall(expression: IrCall): IrExpression = + super.visitCall(expression.createSuspendFunctionCallViewIfNeeded(context, it, callerIsInlineLambda = false)) + }) + } } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 8ed785a893d..437036ce233 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -208,6 +208,13 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { } } + if (function.isSuspend && function.origin != JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW && + function.origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW && + (function.parent as? IrClass)?.origin != JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL + ) { + return mapSignature(function.suspendFunctionView(context, false), skipGenericSignature) + } + val sw = if (skipGenericSignature) JvmSignatureWriter() else BothSignatureWriter(BothSignatureWriter.Mode.METHOD) typeMapper.writeFormalTypeParameters(function.typeParameters, sw) diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt index e70a8df6413..2c5f0915c00 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FULL_JDK // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt index 4a18e1c9b4d..dfe44107c4d 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override2.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FULL_JDK // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt index 948463c0100..c20e5b85db2 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override3.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FULL_JDK // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt index 7a53634ef7d..a0395223c16 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override4.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FULL_JDK // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt index c9bd9c70e1f..408d6e22ea7 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FULL_JDK // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5_ir.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5_ir.txt new file mode 100644 index 00000000000..8c05d7c0688 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override5_ir.txt @@ -0,0 +1,87 @@ +@kotlin.Metadata +public interface Base { + public abstract @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata +final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$1 { + field L$0: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + synthetic final field this$0: Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1 + public method (p0: Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1, p1: kotlin.coroutines.Continuation): void + public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object +} + +@kotlin.Metadata +public final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$2 { + inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1 + inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$2 + public method (): void + public synthetic @org.jetbrains.annotations.Nullable method invoke(): java.lang.Object + public final method invoke(): void +} + +@kotlin.Metadata +public final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1 { + inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1 + inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$2 + public method (): void + public @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object + public @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.coroutines.jvm.internal.DebugMetadata +@kotlin.Metadata +final class Override5Kt$box$1 { + private field label: int + inner class Override5Kt$box$1 + public method (p0: kotlin.coroutines.Continuation): void + public final @org.jetbrains.annotations.NotNull method create(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): kotlin.coroutines.Continuation + public final method invoke(p0: java.lang.Object): java.lang.Object + public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object +} + +@kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata +final class Override5Kt$inlineMe$1$generic$1 { + field L$0: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + private field this$0: Override5Kt$inlineMe$1 + public method (p0: Override5Kt$inlineMe$1, p1: kotlin.coroutines.Continuation): void + public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object +} + +@kotlin.Metadata +public final class Override5Kt$inlineMe$1$generic$2 { + inner class Override5Kt$inlineMe$1 + inner class Override5Kt$inlineMe$1$generic$2 + public method (): void + public synthetic @org.jetbrains.annotations.Nullable method invoke(): java.lang.Object + public final method invoke(): void +} + +@kotlin.Metadata +public final class Override5Kt$inlineMe$1 { + private synthetic final field $c: kotlin.jvm.functions.Function1 + inner class Override5Kt$inlineMe$1 + inner class Override5Kt$inlineMe$1$generic$2 + public method (p0: kotlin.jvm.functions.Function1): void + public @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object + public @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +public final class Override5Kt { + private static field c: kotlin.coroutines.Continuation + inner class Override5Kt$box$1 + inner class Override5Kt$inlineMe$1 + public final static method (): void + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String + public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void + public final static @org.jetbrains.annotations.Nullable method getC(): kotlin.coroutines.Continuation + public final static @org.jetbrains.annotations.NotNull method inlineMe(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): Base + public final static method setC(@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): void +} diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt index ecae95eb9a6..62f7bbc97cd 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/override6.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FULL_JDK // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt index 469541625b6..82d78a8b158 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideCrossinline.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FULL_JDK // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt index 5bf9d302cdc..76c041723f9 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/overrideOverriden.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FULL_JDK // WITH_RUNTIME // WITH_COROUTINES