diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index e87adfb86a9..87eba83702a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -80,7 +80,6 @@ import static org.jetbrains.kotlin.descriptors.ModalityKt.isOverridable; import static org.jetbrains.kotlin.load.java.JvmAbi.LOCAL_VARIABLE_INLINE_ARGUMENT_SYNTHETIC_LINE_NUMBER; import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; -import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isEffectivelyInlineOnly; import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isInlineOnlyPrivateInBytecode; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; import static org.jetbrains.kotlin.resolve.jvm.InlineClassManglingRulesKt.shouldHideConstructorDueToInlineClassTypeValueParameters; @@ -124,18 +123,14 @@ public class FunctionCodegen { if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) { FunctionGenerationStrategy strategy; if (functionDescriptor.isSuspend()) { - if (isEffectivelyInlineOnly(functionDescriptor)) { - strategy = new FunctionGenerationStrategy.FunctionDefault(state, function); - } else { - strategy = new SuspendFunctionGenerationStrategy( - state, - CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(functionDescriptor), - function, - v.getThisName(), - state.getConstructorCallNormalizationMode(), - this - ); - } + strategy = new SuspendFunctionGenerationStrategy( + state, + CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(functionDescriptor), + function, + v.getThisName(), + state.getConstructorCallNormalizationMode(), + this + ); } else { strategy = new FunctionGenerationStrategy.FunctionDefault(state, function); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt index e8b1ce18c42..d14c2057ed8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext +import org.jetbrains.kotlin.resolve.inline.isEffectivelyInlineOnly import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature @@ -56,6 +57,9 @@ class SuspendFunctionGenerationStrategy( override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor { if (access and Opcodes.ACC_ABSTRACT != 0) return mv + if (originalSuspendDescriptor.isEffectivelyInlineOnly()) { + return SuspendForInlineOnlyMethodVisitor(mv, access, name, desc) + } val stateMachineBuilder = createStateMachineBuilder(mv, access, name, desc) if (originalSuspendDescriptor.isInline) { return SuspendForInlineCopyingMethodVisitor(stateMachineBuilder, access, name, desc, functionCodegen::newMethod, keepAccess = false) @@ -156,6 +160,13 @@ class SuspendFunctionGenerationStrategy( } } +private class SuspendForInlineOnlyMethodVisitor(delegate: MethodVisitor, access: Int, name: String, desc: String) : + TransformationMethodVisitor(delegate, access, name, desc, null, null) { + override fun performTransformations(methodNode: MethodNode) { + methodNode.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false) + } +} + // For named suspend function we generate two methods: // 1) to use as noinline function, which have state machine // 2) to use from inliner: private one without state machine diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 9a4b217698e..9e26252dc61 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -355,7 +355,7 @@ class ClassCodegen private constructor( val (node, smap) = generateMethodNode(method) node.preprocessSuspendMarkers( - method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE, + method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE || method.isEffectivelyInlineOnly(), method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE ) val mv = with(node) { visitor.newMethod(method.OtherOrigin, access, name, desc, signature, exceptions.toTypedArray()) } diff --git a/compiler/testData/codegen/bytecodeText/coroutines/effectivelyInlineOnly.kt b/compiler/testData/codegen/bytecodeText/coroutines/effectivelyInlineOnly.kt new file mode 100644 index 00000000000..ec20ea0be00 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/effectivelyInlineOnly.kt @@ -0,0 +1,4 @@ +// WITH_COROUTINES +// TREAT_AS_ONE_FILE +inline suspend fun f(x: suspend () -> T) = x() +// 0 InlineMarker diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index bd47e602c31..d830af1907e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1391,6 +1391,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/coroutines/doNotReassignContinuation.kt"); } + @TestMetadata("effectivelyInlineOnly.kt") + public void testEffectivelyInlineOnly() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/effectivelyInlineOnly.kt"); + } + @TestMetadata("nonLocalReturn.kt") public void testNonLocalReturn() throws Exception { runTest("compiler/testData/codegen/bytecodeText/coroutines/nonLocalReturn.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index 4a5f3894dc0..caf60eff763 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -1401,6 +1401,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/coroutines/doNotReassignContinuation.kt"); } + @TestMetadata("effectivelyInlineOnly.kt") + public void testEffectivelyInlineOnly() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/effectivelyInlineOnly.kt"); + } + @TestMetadata("nonLocalReturn.kt") public void testNonLocalReturn() throws Exception { runTest("compiler/testData/codegen/bytecodeText/coroutines/nonLocalReturn.kt");