diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 4aacd7e8b4c..df3fad4899a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenForLambda; import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor; +import org.jetbrains.kotlin.codegen.coroutines.SuspensionPointKind; import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; import org.jetbrains.kotlin.codegen.inline.*; import org.jetbrains.kotlin.codegen.intrinsics.*; @@ -2592,11 +2593,12 @@ public class ExpressionCodegen extends KtVisitor impleme return; } - boolean isSuspendNoInlineCall = - CoroutineCodegenUtilKt.isSuspendNoInlineCall(resolvedCall, this, state.getLanguageVersionSettings()); + SuspensionPointKind suspensionPointKind = + CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, this, state.getLanguageVersionSettings()); + boolean maybeSuspensionPoint = suspensionPointKind != SuspensionPointKind.NEVER; boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor; if (!(callableMethod instanceof IntrinsicWithSpecialReceiver)) { - putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, isSuspendNoInlineCall, isConstructor); + putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, maybeSuspensionPoint, isConstructor); } callGenerator.processAndPutHiddenParameters(false); @@ -2630,16 +2632,16 @@ public class ExpressionCodegen extends KtVisitor impleme } } - if (isSuspendNoInlineCall) { - addSuspendMarker(v, true); + if (maybeSuspensionPoint) { + addSuspendMarker(v, suspensionPointKind, true); } callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this); - if (isSuspendNoInlineCall) { + if (maybeSuspensionPoint) { addReturnsUnitMarkerIfNecessary(v, resolvedCall); - addSuspendMarker(v, false); + addSuspendMarker(v, suspensionPointKind, false); addInlineMarker(v, false); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 56538a1be66..e87adfb86a9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -19,7 +19,6 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy; -import org.jetbrains.kotlin.codegen.coroutines.SuspendInlineFunctionGenerationStrategy; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt; @@ -127,17 +126,8 @@ public class FunctionCodegen { if (functionDescriptor.isSuspend()) { if (isEffectivelyInlineOnly(functionDescriptor)) { strategy = new FunctionGenerationStrategy.FunctionDefault(state, function); - } else if (!functionDescriptor.isInline()) { - strategy = new SuspendFunctionGenerationStrategy( - state, - CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(functionDescriptor), - function, - v.getThisName(), - state.getConstructorCallNormalizationMode(), - this - ); } else { - strategy = new SuspendInlineFunctionGenerationStrategy( + strategy = new SuspendFunctionGenerationStrategy( state, CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(functionDescriptor), function, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index f3135f724e6..58e373b5261 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding.CAPTURES_CROSSINLINE_ import org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE import org.jetbrains.kotlin.codegen.context.ClosureContext import org.jetbrains.kotlin.codegen.context.MethodContext -import org.jetbrains.kotlin.codegen.inline.coroutines.SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.codegen.state.GenerationState @@ -501,17 +500,11 @@ class CoroutineCodegenForLambda private constructor( languageVersionSettings = languageVersionSettings, disableTailCallOptimizationForFunctionReturningUnit = false ) - return if (forInline) AddEndLabelMethodVisitor( - MethodNodeCopyingMethodVisitor( - SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( - stateMachineBuilder, access, name, desc, v.thisName, - isCapturedSuspendLambda = { isCapturedSuspendLambda(closure, it.name, state.bindingContext) } - ), access, name, desc, - newMethod = { origin, newAccess, newName, newDesc -> - functionCodegen.newMethod(origin, newAccess, newName, newDesc, null, null) - } - ), access, name, desc, endLabel - ) else AddEndLabelMethodVisitor(stateMachineBuilder, access, name, desc, endLabel) + val maybeWithForInline = if (forInline) + SuspendForInlineCopyingMethodVisitor(stateMachineBuilder, access, name, desc, functionCodegen::newMethod) + else + stateMachineBuilder + return AddEndLabelMethodVisitor(maybeWithForInline, access, name, desc, endLabel) } override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { 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 e561b11b4b7..e8b1ce18c42 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt @@ -9,7 +9,8 @@ import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.inline.addFakeContinuationConstructorCallMarker -import org.jetbrains.kotlin.codegen.inline.coroutines.SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor +import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX +import org.jetbrains.kotlin.codegen.inline.preprocessSuspendMarkers import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode import org.jetbrains.kotlin.config.LanguageVersionSettings @@ -18,23 +19,23 @@ 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.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.utils.addToStdlib.safeAs -import org.jetbrains.kotlin.utils.sure import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.tree.MethodNode -open class SuspendFunctionGenerationStrategy( +class SuspendFunctionGenerationStrategy( state: GenerationState, - protected val originalSuspendDescriptor: FunctionDescriptor, - protected val declaration: KtFunction, - protected val containingClassInternalName: String, + private val originalSuspendDescriptor: FunctionDescriptor, + private val declaration: KtFunction, + private val containingClassInternalName: String, private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode, - protected val functionCodegen: FunctionCodegen + private val functionCodegen: FunctionCodegen ) : FunctionGenerationStrategy.CodegenBased(state) { private lateinit var codegen: ExpressionCodegen @@ -56,39 +57,23 @@ open class SuspendFunctionGenerationStrategy( if (access and Opcodes.ACC_ABSTRACT != 0) return mv val stateMachineBuilder = createStateMachineBuilder(mv, access, name, desc) - - val forInline = state.bindingContext[CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA, originalSuspendDescriptor] == true - // Both capturing and inline functions share the same suffix, however, inline functions can also be capturing - // they are already covered by SuspendInlineFunctionGenerationStrategy, thus, if we generate yet another copy, - // we will get name+descriptor clash - return if (forInline && !originalSuspendDescriptor.isInline) - AddConstructorCallForCoroutineRegeneration( - MethodNodeCopyingMethodVisitor( - SurroundSuspendLambdaCallsWithSuspendMarkersMethodVisitor( - stateMachineBuilder, - access, name, desc, containingClassInternalName, - isCapturedSuspendLambda = { - isCapturedSuspendLambda( - functionCodegen.closure.sure { - "Anonymous object should have closure" - }, - it.name, - state.bindingContext - ) - } - ), access, name, desc, - newMethod = { origin, newAccess, newName, newDesc -> - functionCodegen.newMethod(origin, newAccess, newName, newDesc, null, null) - } - ), access, name, desc, null, null, this::classBuilderForCoroutineState, + if (originalSuspendDescriptor.isInline) { + return SuspendForInlineCopyingMethodVisitor(stateMachineBuilder, access, name, desc, functionCodegen::newMethod, keepAccess = false) + } + if (state.bindingContext[CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA, originalSuspendDescriptor] == true) { + return AddConstructorCallForCoroutineRegeneration( + SuspendForInlineCopyingMethodVisitor(stateMachineBuilder, access, name, desc, functionCodegen::newMethod), + access, name, desc, null, null, this::classBuilderForCoroutineState, containingClassInternalName, originalSuspendDescriptor.dispatchReceiverParameter != null, containingClassInternalNameOrNull(), languageVersionSettings - ) else stateMachineBuilder + ) + } + return stateMachineBuilder } - protected fun createStateMachineBuilder( + private fun createStateMachineBuilder( mv: MethodVisitor, access: Int, name: String, @@ -170,3 +155,28 @@ open class SuspendFunctionGenerationStrategy( } } } + +// 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 +class SuspendForInlineCopyingMethodVisitor( + delegate: MethodVisitor, access: Int, name: String, desc: String, + private val newMethod: (JvmDeclarationOrigin, Int, String, String, String?, Array?) -> MethodVisitor, + private val keepAccess: Boolean = true +) : TransformationMethodVisitor(delegate, access, name, desc, null, null) { + override fun performTransformations(methodNode: MethodNode) { + val newMethodNode = with(methodNode) { + val newAccess = if (keepAccess) access else + access or Opcodes.ACC_PRIVATE and Opcodes.ACC_PUBLIC.inv() and Opcodes.ACC_PROTECTED.inv() + MethodNode(newAccess, name + FOR_INLINE_SUFFIX, desc, signature, exceptions.toTypedArray()) + } + val newMethodVisitor = with(newMethodNode) { + newMethod(JvmDeclarationOrigin.NO_ORIGIN, access, name, desc, signature, exceptions.toTypedArray()) + } + methodNode.instructions.resetLabels() + methodNode.accept(newMethodNode) + methodNode.preprocessSuspendMarkers(forInline = false, keepFakeContinuation = false) + newMethodNode.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = true) + newMethodNode.accept(newMethodVisitor) + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt deleted file mode 100644 index 601f98fff31..00000000000 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.codegen.coroutines - -import org.jetbrains.kotlin.builtins.isSuspendFunctionType -import org.jetbrains.kotlin.codegen.ExpressionCodegen -import org.jetbrains.kotlin.codegen.FunctionCodegen -import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy -import org.jetbrains.kotlin.codegen.TransformationMethodVisitor -import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX -import org.jetbrains.kotlin.codegen.inline.coroutines.findReceiverOfInvoke -import org.jetbrains.kotlin.codegen.inline.coroutines.surroundInvokesWithSuspendMarkers -import org.jetbrains.kotlin.codegen.inline.isInvokeOnLambda -import org.jetbrains.kotlin.codegen.optimization.common.asSequence -import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer -import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer -import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.psi.KtFunction -import org.jetbrains.kotlin.resolve.inline.InlineUtil -import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature -import org.jetbrains.org.objectweb.asm.MethodVisitor -import org.jetbrains.org.objectweb.asm.Opcodes -import org.jetbrains.org.objectweb.asm.tree.* -import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter - -// 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 -class SuspendInlineFunctionGenerationStrategy( - state: GenerationState, - originalSuspendDescriptor: FunctionDescriptor, - declaration: KtFunction, - containingClassInternalName: String, - constructorCallNormalizationMode: JVMConstructorCallNormalizationMode, - codegen: FunctionCodegen -) : SuspendFunctionGenerationStrategy( - state, - originalSuspendDescriptor, - declaration, - containingClassInternalName, - constructorCallNormalizationMode, - codegen -) { - private val defaultStrategy = FunctionGenerationStrategy.FunctionDefault(state, declaration) - - override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor { - if (access and Opcodes.ACC_ABSTRACT != 0) return mv - - return MethodNodeCopyingMethodVisitor( - SurroundSuspendParameterCallsWithSuspendMarkersMethodVisitor( - createStateMachineBuilder(mv, access, name, desc), - access, name, desc, containingClassInternalName, originalSuspendDescriptor.valueParameters - ), access, name, desc, - newMethod = { origin, newAccess, newName, newDesc -> - functionCodegen.newMethod(origin, newAccess, newName, newDesc, null, null) - }, keepAccess = false - ) - } - - override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { - super.doGenerateBody(codegen, signature) - defaultStrategy.doGenerateBody(codegen, signature) - } -} - -class MethodNodeCopyingMethodVisitor( - delegate: MethodVisitor, private val access: Int, private val name: String, private val desc: String, - private val newMethod: (JvmDeclarationOrigin, Int, String, String) -> MethodVisitor, - private val keepAccess: Boolean = true -) : TransformationMethodVisitor( - delegate, calculateAccessForInline(access, keepAccess), "$name$FOR_INLINE_SUFFIX", desc, null, null -) { - override fun performTransformations(methodNode: MethodNode) { - val newMethodNode = newMethod( - JvmDeclarationOrigin.NO_ORIGIN, calculateAccessForInline(access, keepAccess), "$name$FOR_INLINE_SUFFIX", desc - ) - methodNode.instructions.resetLabels() - methodNode.accept(newMethodNode) - } - - companion object { - private fun calculateAccessForInline(access: Int, keepAccess: Boolean): Int = - if (keepAccess) access - else access or Opcodes.ACC_PRIVATE and Opcodes.ACC_PUBLIC.inv() and Opcodes.ACC_PROTECTED.inv() - } -} - -private class SurroundSuspendParameterCallsWithSuspendMarkersMethodVisitor( - delegate: MethodVisitor, - access: Int, - name: String, - desc: String, - private val thisName: String, - private val valueParameters: List -): TransformationMethodVisitor(delegate, access, name, desc, null, null) { - override fun performTransformations(methodNode: MethodNode) { - fun AbstractInsnNode.index() = methodNode.instructions.indexOf(this) - fun AbstractInsnNode.isInlineSuspendParameter(): Boolean { - if (this !is VarInsnNode) return false - val index = `var` - (if (methodNode.access and Opcodes.ACC_STATIC != 0) 0 else 1) - return opcode == Opcodes.ALOAD && index < valueParameters.size && InlineUtil.isInlineParameter(valueParameters[index]) && - valueParameters[index].type.isSuspendFunctionType - } - - FixStackMethodTransformer().transform(thisName, methodNode) - - val sourceFrames = MethodTransformer.analyze(thisName, methodNode, SourceInterpreter()) - - val noinlineInvokes = arrayListOf>() - - for (insn in methodNode.instructions.asSequence()) { - if (insn.opcode != Opcodes.INVOKEINTERFACE) continue - insn as MethodInsnNode - if (!isInvokeOnLambda(insn.owner, insn.name)) continue - val frame = sourceFrames[insn.index()] ?: continue - val aload = findReceiverOfInvoke(frame, insn).takeIf { it?.isInlineSuspendParameter() == true } as? VarInsnNode ?: continue - noinlineInvokes.add(insn to aload) - } - - surroundInvokesWithSuspendMarkers(methodNode, noinlineInvokes) - } -} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt index 311867acbe1..307e8286b7e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -219,15 +219,18 @@ private fun NewResolvedCallImpl.asDummyOldResolvedCall(bindi ) } -fun ResolvedCall<*>.isSuspendNoInlineCall(codegen: ExpressionCodegen, languageVersionSettings: LanguageVersionSettings): Boolean { +enum class SuspensionPointKind { NEVER, NOT_INLINE, ALWAYS } + +fun ResolvedCall<*>.isSuspensionPoint(codegen: ExpressionCodegen, languageVersionSettings: LanguageVersionSettings): SuspensionPointKind { + val functionDescriptor = resultingDescriptor as? FunctionDescriptor ?: return SuspensionPointKind.NEVER + if (!functionDescriptor.unwrapInitialDescriptorForSuspendFunction().isSuspend) return SuspensionPointKind.NEVER + if (functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings)) return SuspensionPointKind.ALWAYS + if (functionDescriptor.isInline) return SuspensionPointKind.NEVER + val isInlineLambda = this.safeAs() ?.variableCall?.resultingDescriptor?.safeAs() ?.let { it.isCrossinline || (!it.isNoinline && codegen.context.functionDescriptor.isInline) } == true - - val functionDescriptor = resultingDescriptor as? FunctionDescriptor ?: return false - if (!functionDescriptor.unwrapInitialDescriptorForSuspendFunction().isSuspend) return false - if (functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings)) return true - return !(functionDescriptor.isInline || isInlineLambda) + return if (isInlineLambda) SuspensionPointKind.NOT_INLINE else SuspensionPointKind.ALWAYS } fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index cb60ed3dd95..a68057b3eb1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -534,7 +534,9 @@ abstract class InlineCodegen( val directMember = getDirectMemberAndCallableFromObject(functionDescriptor) if (!isBuiltInArrayIntrinsic(functionDescriptor) && directMember !is DescriptorWithContainerSource) { - return sourceCompilerForInline.doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, callDefault, asmMethod) + val node = sourceCompilerForInline.doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, callDefault, asmMethod) + node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false) + return node } return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index 567813940b1..f78d519e412 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -222,6 +222,7 @@ internal fun Type.boxReceiverForBoundReference(kotlinType: KotlinType, typeMappe abstract class ExpressionLambda(isCrossInline: Boolean) : LambdaInfo(isCrossInline) { override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) { node = sourceCompiler.generateLambdaBody(this) + node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false) } abstract fun getInlineSuspendLambdaViewDescriptor(): FunctionDescriptor 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 ac851edb6c5..0cefda1054c 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 @@ -107,15 +107,7 @@ class CoroutineTransformer( ) if (generateForInline) - MethodNodeCopyingMethodVisitor( - delegate = stateMachineBuilder, - access = node.access, - name = name, - desc = node.desc, - newMethod = { origin, newAccess, newName, newDesc -> - classBuilder.newMethod(origin, newAccess, newName, newDesc, null, null) - } - ) + SuspendForInlineCopyingMethodVisitor(stateMachineBuilder, node.access, name, node.desc, classBuilder::newMethod) else stateMachineBuilder } @@ -154,12 +146,7 @@ class CoroutineTransformer( ) if (generateForInline) - MethodNodeCopyingMethodVisitor( - stateMachineBuilder, node.access, name, node.desc, - newMethod = { origin, newAccess, newName, newDesc -> - classBuilder.newMethod(origin, newAccess, newName, newDesc, null, null) - } - ) + SuspendForInlineCopyingMethodVisitor(stateMachineBuilder, node.access, name, node.desc, classBuilder::newMethod) else stateMachineBuilder } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index bbebb29cd96..dde4227c56e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -18,7 +18,10 @@ import org.jetbrains.kotlin.codegen.context.CodegenContext import org.jetbrains.kotlin.codegen.context.CodegenContextUtil import org.jetbrains.kotlin.codegen.context.InlineLambdaContext import org.jetbrains.kotlin.codegen.context.MethodContext +import org.jetbrains.kotlin.codegen.coroutines.SuspensionPointKind import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction +import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence +import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.optimization.common.intConstant import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper @@ -71,8 +74,8 @@ private const val INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall" private const val INLINE_MARKER_FINALLY_START = "finallyStart" private const val INLINE_MARKER_FINALLY_END = "finallyEnd" -const val INLINE_MARKER_BEFORE_SUSPEND_ID = 0 -const val INLINE_MARKER_AFTER_SUSPEND_ID = 1 +private const val INLINE_MARKER_BEFORE_SUSPEND_ID = 0 +private const val INLINE_MARKER_AFTER_SUSPEND_ID = 1 private const val INLINE_MARKER_RETURNS_UNIT = 2 private const val INLINE_MARKER_FAKE_CONTINUATION = 3 private const val INLINE_MARKER_BEFORE_FAKE_CONTINUATION_CONSTRUCTOR_CALL = 4 @@ -437,8 +440,10 @@ fun addInlineSuspendMarker(v: InstructionAdapter, isStartNotEnd: Boolean) { v.emitInlineMarker(if (isStartNotEnd) INLINE_MARKER_BEFORE_INLINE_SUSPEND_ID else INLINE_MARKER_AFTER_INLINE_SUSPEND_ID) } -fun addSuspendMarker(v: InstructionAdapter, isStartNotEnd: Boolean, isInline: Boolean) { - if (isInline) addInlineSuspendMarker(v, isStartNotEnd) else addSuspendMarker(v, isStartNotEnd) +fun addSuspendMarker(v: InstructionAdapter, kind: SuspensionPointKind, isStartNotEnd: Boolean) = when (kind) { + SuspensionPointKind.NEVER -> Unit + SuspensionPointKind.NOT_INLINE -> addInlineSuspendMarker(v, isStartNotEnd) + SuspensionPointKind.ALWAYS -> addSuspendMarker(v, isStartNotEnd) } fun addFakeContinuationConstructorCallMarker(v: InstructionAdapter, isStartNotEnd: Boolean) { @@ -466,16 +471,16 @@ private fun InstructionAdapter.emitInlineMarker(id: Int) { internal fun isBeforeSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_BEFORE_SUSPEND_ID) internal fun isAfterSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_AFTER_SUSPEND_ID) -fun isBeforeInlineSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_BEFORE_INLINE_SUSPEND_ID) -fun isAfterInlineSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_AFTER_INLINE_SUSPEND_ID) +internal fun isBeforeInlineSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_BEFORE_INLINE_SUSPEND_ID) +internal fun isAfterInlineSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_AFTER_INLINE_SUSPEND_ID) internal fun isReturnsUnitMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_RETURNS_UNIT) internal fun isFakeContinuationMarker(insn: AbstractInsnNode) = insn.previous != null && isSuspendMarker(insn.previous, INLINE_MARKER_FAKE_CONTINUATION) && insn.opcode == Opcodes.ACONST_NULL -fun isBeforeFakeContinuationConstructorCallMarker(insn: AbstractInsnNode) = +internal fun isBeforeFakeContinuationConstructorCallMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_BEFORE_FAKE_CONTINUATION_CONSTRUCTOR_CALL) -fun isAfterFakeContinuationConstructorCallMarker(insn: AbstractInsnNode) = +internal fun isAfterFakeContinuationConstructorCallMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_AFTER_FAKE_CONTINUATION_CONSTRUCTOR_CALL) private fun isSuspendMarker(insn: AbstractInsnNode, id: Int) = @@ -563,3 +568,30 @@ fun initDefaultSourceMappingIfNeeded( parentContext = parentContext.parentContext } } + +fun MethodNode.preprocessSuspendMarkers(forInline: Boolean, keepFakeContinuation: Boolean = true) { + if (instructions.first == null) return + if (!keepFakeContinuation) { + val sequence = instructions.asSequence() + val start = sequence.find { isBeforeFakeContinuationConstructorCallMarker(it) } + val end = sequence.find { isAfterFakeContinuationConstructorCallMarker(it) } + if (start != null) { + // Include one instruction before the start marker (that's the id) and one after the end marker (that's a pop). + InsnSequence(start.previous, end?.next?.next).forEach(instructions::remove) + } + } + for (insn in instructions.asSequence().filter { isBeforeInlineSuspendMarker(it) || isAfterInlineSuspendMarker(it) }) { + if (forInline || keepFakeContinuation) { + val beforeMarker = insn.previous.previous + if (isReturnsUnitMarker(beforeMarker)) { + instructions.remove(beforeMarker.previous) + instructions.remove(beforeMarker) + } + instructions.remove(insn.previous) + instructions.remove(insn) + } else { + val newId = if (isBeforeInlineSuspendMarker(insn)) INLINE_MARKER_BEFORE_SUSPEND_ID else INLINE_MARKER_AFTER_SUSPEND_ID + instructions.set(insn.previous, InsnNode(Opcodes.ICONST_0 + newId)) + } + } +} 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 ce8dc97e8ed..ab9684a6568 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 @@ -12,10 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField import org.jetbrains.kotlin.backend.jvm.lower.hasAssertionsDisabledField import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding -import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper -import org.jetbrains.kotlin.codegen.inline.NameGenerator -import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages -import org.jetbrains.kotlin.codegen.inline.SourceMapper +import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.config.LanguageFeature @@ -355,7 +352,10 @@ open class ClassCodegen protected constructor( } val node = FunctionCodegen(method, this).generate() - node.preprocessSuspendMarkers(method) + node.preprocessSuspendMarkers( + method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE, + method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE + ) val mv = with(node) { visitor.newMethod(method.OtherOrigin, access, name, desc, signature, exceptions.toTypedArray()) } if (method.hasContinuation() || method.isInvokeSuspendOfLambda()) { // Generate a state machine within this method. The continuation class for it should be generated 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 1a807409687..3149f8f7fb3 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 @@ -16,10 +16,7 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_IMPL_NAME_SUFFIX import org.jetbrains.kotlin.codegen.coroutines.reportSuspensionPointInsideMonitor -import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX -import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence -import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* @@ -35,8 +32,6 @@ import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.types.Variance import org.jetbrains.org.objectweb.asm.MethodVisitor -import org.jetbrains.org.objectweb.asm.Opcodes -import org.jetbrains.org.objectweb.asm.tree.InsnNode import org.jetbrains.org.objectweb.asm.tree.MethodNode internal fun MethodNode.acceptWithStateMachine( @@ -159,30 +154,3 @@ internal fun createFakeContinuation(context: JvmBackendContext): IrExpression = context.ir.symbols.continuationClass.createType(true, listOf(makeTypeProjection(context.irBuiltIns.anyNType, Variance.INVARIANT))), "FAKE_CONTINUATION" ) - -fun MethodNode.preprocessSuspendMarkers(method: IrFunction? = null) { - if (instructions.first == null) return - if (method?.origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE) { - // Remove the fake continuation constructor, since this method either has a real state machine or is inline. - // Include one instruction before the start marker (that's the id) and one after the end marker (that's a pop). - val sequence = instructions.asSequence() - val start = sequence.firstOrNull { it.next != null && isBeforeFakeContinuationConstructorCallMarker(it.next) } - if (start != null) { - val end = sequence.first { it.previous != null && isAfterFakeContinuationConstructorCallMarker(it.previous) } - InsnSequence(start, end.next).forEach(instructions::remove) - } - } - // Method is null if this node is going to be inlined into another node rather than written into a class file. - val keepMarkers = method != null && - method.origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE && - method.origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE - for (insn in instructions.asSequence().filter { isBeforeInlineSuspendMarker(it) || isAfterInlineSuspendMarker(it) }) { - if (keepMarkers) { - val newId = if (isBeforeInlineSuspendMarker(insn)) INLINE_MARKER_BEFORE_SUSPEND_ID else INLINE_MARKER_AFTER_SUSPEND_ID - instructions.set(insn.previous, InsnNode(Opcodes.ICONST_0 + newId)) - } else { - instructions.remove(insn.previous) - instructions.remove(insn) - } - } -} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 3c0eedb3b2f..83ab1b2d2dc 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil.* import org.jetbrains.kotlin.codegen.BaseExpressionCodegen import org.jetbrains.kotlin.codegen.CallGenerator import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.coroutines.SuspensionPointKind import org.jetbrains.kotlin.codegen.extractReificationArgument import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.putNeedClassReificationMarker @@ -429,7 +430,7 @@ class ExpressionCodegen( expression.markLineNumber(true) if (isSuspensionPoint != SuspensionPointKind.NEVER) { - addSuspendMarker(mv, isStartNotEnd = true, isInline = isSuspensionPoint == SuspensionPointKind.NOT_INLINE) + addSuspendMarker(mv, isSuspensionPoint, isStartNotEnd = true) } if (irFunction.isInvokeSuspendOfContinuation()) { @@ -442,7 +443,7 @@ class ExpressionCodegen( } if (isSuspensionPoint != SuspensionPointKind.NEVER) { - addSuspendMarker(mv, isStartNotEnd = false, isInline = isSuspensionPoint == SuspensionPointKind.NOT_INLINE) + addSuspendMarker(mv, isSuspensionPoint, isStartNotEnd = false) addInlineMarker(mv, isStartNotEnd = false) } @@ -478,8 +479,6 @@ class ExpressionCodegen( } } - private enum class SuspensionPointKind { NEVER, NOT_INLINE, ALWAYS } - private fun IrFunctionAccessExpression.isSuspensionPoint(): SuspensionPointKind = when { !symbol.owner.isSuspend || !irFunction.shouldContainSuspendMarkers() -> SuspensionPointKind.NEVER // Copy-pasted bytecode blocks are not suspension points. diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt index ea6c6a69ad2..35ad2490108 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt @@ -95,7 +95,6 @@ class IrSourceCompilerForInline( override fun generateLambdaBody(lambdaInfo: ExpressionLambda): SMAPAndMethodNode { val smap = codegen.context.getSourceMapper(codegen.classCodegen.irClass) val node = FunctionCodegen((lambdaInfo as IrExpressionLambdaImpl).function, codegen.classCodegen, codegen).generate(smap) - node.preprocessSuspendMarkers() return SMAPAndMethodNode(node, SMAP(smap.resultMappings)) } @@ -108,7 +107,6 @@ class IrSourceCompilerForInline( assert(callableDescriptor == callee.symbol.descriptor.original) { "Expected $callableDescriptor got ${callee.descriptor.original}" } val classCodegen = FakeClassCodegen(callee, codegen.classCodegen) val node = FunctionCodegen(callee, classCodegen).generate() - node.preprocessSuspendMarkers() return SMAPAndMethodNode(node, SMAP(classCodegen.getOrCreateSourceMapper().resultMappings)) } diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.txt index e8cb1d1f635..353cb1b67cc 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.txt @@ -272,35 +272,6 @@ public final class CrossinlineKt$fold$$inlined$consumeEach$1 { public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object } -@kotlin.Metadata -@kotlin.coroutines.jvm.internal.DebugMetadata -public final class CrossinlineKt$fold$$inlined$consumeEach$2$1 { - field L$0: java.lang.Object - field L$1: java.lang.Object - field L$2: java.lang.Object - field L$3: java.lang.Object - field L$4: java.lang.Object - field label: int - synthetic field result: java.lang.Object - synthetic final field this$0: CrossinlineKt$fold$$inlined$consumeEach$2 - inner class CrossinlineKt$fold$$inlined$consumeEach$2 - inner class CrossinlineKt$fold$$inlined$consumeEach$2$1 - public method (p0: CrossinlineKt$fold$$inlined$consumeEach$2, 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 CrossinlineKt$fold$$inlined$consumeEach$2 { - synthetic final field $acc$inlined: kotlin.jvm.internal.Ref$ObjectRef - synthetic final field $operation$inlined: kotlin.jvm.functions.Function3 - inner class CrossinlineKt$fold$$inlined$consumeEach$2 - inner class CrossinlineKt$fold$$inlined$consumeEach$2$1 - public method (p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function3): void - public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void - public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object - public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object -} - @kotlin.Metadata @kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$fold$1 { diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_1_2.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_1_2.txt index 9a3c8b6af5d..5dab4b2ef5a 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_1_2.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_1_2.txt @@ -280,36 +280,6 @@ public final class CrossinlineKt$fold$$inlined$consumeEach$1 { public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object } -@kotlin.Metadata -public final class CrossinlineKt$fold$$inlined$consumeEach$2$1 { - field L$0: java.lang.Object - field L$1: java.lang.Object - field L$2: java.lang.Object - field L$3: java.lang.Object - field L$4: java.lang.Object - synthetic field data: java.lang.Object - synthetic field exception: java.lang.Throwable - synthetic final field this$0: CrossinlineKt$fold$$inlined$consumeEach$2 - inner class CrossinlineKt$fold$$inlined$consumeEach$2 - inner class CrossinlineKt$fold$$inlined$consumeEach$2$1 - public method (p0: CrossinlineKt$fold$$inlined$consumeEach$2, p1: 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 CrossinlineKt$fold$$inlined$consumeEach$2 { - synthetic final field $acc$inlined: kotlin.jvm.internal.Ref$ObjectRef - synthetic final field $operation$inlined: kotlin.jvm.functions.Function3 - inner class CrossinlineKt$fold$$inlined$consumeEach$2 - inner class CrossinlineKt$fold$$inlined$consumeEach$2$1 - public method (p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function3): void - public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void - public @org.jetbrains.annotations.Nullable method send$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object - public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object -} - @kotlin.Metadata public final class CrossinlineKt$fold$1 { field L$0: java.lang.Object diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/suspendInlineCycle.kt b/compiler/testData/diagnostics/testsWithJvmBackend/suspendInlineCycle.kt index b4f578bf008..399ec143b5f 100644 --- a/compiler/testData/diagnostics/testsWithJvmBackend/suspendInlineCycle.kt +++ b/compiler/testData/diagnostics/testsWithJvmBackend/suspendInlineCycle.kt @@ -1,11 +1,11 @@ // !RENDER_DIAGNOSTICS_FULL_TEXT -// Note: 4 diagnostics per call because there are 2 synthetic $$forInline methods. +// TARGET_BACKEND: JVM_OLD suspend inline fun inlineFun1(p: () -> Unit) { p() - inlineFun2(p) + inlineFun2(p) } suspend inline fun inlineFun2(p: () -> Unit) { p() - inlineFun1(p) + inlineFun1(p) } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJvmIrBackendGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJvmIrBackendGenerated.java index 3dd3251c104..362f516a1ca 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJvmIrBackendGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJvmIrBackendGenerated.java @@ -39,11 +39,6 @@ public class DiagnosticsTestWithJvmIrBackendGenerated extends AbstractDiagnostic runTest("compiler/testData/diagnostics/testsWithJvmBackend/inlineCycle.kt"); } - @TestMetadata("suspendInlineCycle.kt") - public void testSuspendInlineCycle() throws Exception { - runTest("compiler/testData/diagnostics/testsWithJvmBackend/suspendInlineCycle.kt"); - } - @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/duplicateJvmSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)