From a1448ebb371e18532732980333fd51a1a945f0af Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Tue, 22 Oct 2019 20:02:34 +0300 Subject: [PATCH] JVM_IR: Support crossinline suspend lambdas The main idea is the following: since we need to generate (fake)continuations before inlining, we move IrClasses of suspend lambdas and continuation classes of named functions into the functions. Thus, it allows the codegen to generate them prior to inlining and the inliner will happily transform them for us. Because of that, lowerings which transform call-site function are likely to change reference to lowered suspend lambdas or functions. Hence, do not rely on references to lowered suspend lambdas or functions, instead, rely on attributes. Do not generate continuation for inline suspend lambdas. Previously, inline suspend lambdas were treated like suspend functions, thus we generated continuations for them. Now we just do not treat them as suspend functions or lambdas during AddContinuationLowering. We should add continuation parameter to them, however. Do not generate secondary constructor for suspend lambdas, otherwise, the inliner is unable to transform them (it requires only one constructor to be present). Generate continuation classes for suspend functions as first statement inside the function. This enables suspend functions in local object inside inline functions. Since we already have attributes inside suspend named functions, we just reuse them to generate continuation class names. This allows us to close the gap between code generated by old back-end and the new one. If a suspend named function captures crossinline lambda, we should generate a template for inliner: a copy of the function without state-machine and a continuation constructor call. The call is needed so the inliner transforms the continuation as well. Refactor CoroutineTransformerMethodVisitor, so it no longer depends on PSI. --- .../codegen/coroutines/CoroutineCodegen.kt | 12 +- .../CoroutineTransformerMethodVisitor.kt | 10 +- .../SuspendFunctionGenerationStrategy.kt | 6 +- .../inline/AnonymousObjectTransformer.kt | 3 +- .../codegen/inline/InlineCallSiteInfo.kt | 3 +- .../kotlin/codegen/inline/MethodInliner.kt | 5 +- .../codegen/inline/SourceCompilerForInline.kt | 9 +- .../inline/coroutines/CoroutineTransformer.kt | 36 +- .../codegen/inline/inlineCodegenUtils.kt | 2 +- .../IrElementTransformerVoidWithContext.kt | 1 + .../kotlin/backend/common/ir/IrUtils.kt | 23 +- .../common/lower/LocalDeclarationsLowering.kt | 16 +- .../declarations/declarationBuilders.kt | 4 +- .../kotlin/backend/jvm/DeclarationOrigins.kt | 20 +- .../kotlin/backend/jvm/JvmBackendContext.kt | 6 +- .../backend/jvm/codegen/ClassCodegen.kt | 13 +- .../backend/jvm/codegen/CoroutineCodegen.kt | 87 +++-- .../backend/jvm/codegen/ExpressionCodegen.kt | 30 +- .../backend/jvm/codegen/FunctionCodegen.kt | 53 ++- .../jvm/codegen/IrSourceCompilerForInline.kt | 21 +- .../backend/jvm/codegen/IrTypeMapper.kt | 2 + .../backend/jvm/codegen/PromisedValue.kt | 5 +- .../jvm/lower/AddContinuationLowering.kt | 367 +++++++++++------- .../jvm/lower/CallableReferenceLowering.kt | 3 - .../psi2ir/generators/FunctionGenerator.kt | 4 - .../ir/declarations/lazy/IrLazyFunction.kt | 5 +- .../bridges/lambdaWithLongReceiver_ir.txt | 21 +- .../lambdaWithMultipleParameters_ir.txt | 21 +- .../inlineGenericFunCalledFromSubclass.kt | 1 - .../coroutines/multiModule/inlineWithJava.kt | 1 - .../inlineWithoutStateMachine_ir.txt | 43 +- .../innerObjectRetransformation.kt | 1 - .../innerObjectRetransformation_ir.txt | 170 ++++++++ ...endLambdaInsideCrossinlineSuspendLambda.kt | 2 - .../boxInline/suspend/enclodingMethod.kt | 1 - .../boxInline/suspend/fileNameInMetadata.kt | 2 - .../inlineOrdinaryOfCrossinlineSuspend.kt | 2 - .../inlineOrdinaryOfNoinlineSuspend.kt | 1 - .../inlineSuspendOfCrossinlineOrdinary.kt | 2 - .../inlineSuspendOfCrossinlineSuspend.kt | 2 - .../inlineSuspendOfNoinlineOrdinary.kt | 2 - .../suspend/inlineSuspendOfNoinlineSuspend.kt | 2 - .../suspend/inlineSuspendOfOrdinary.kt | 2 - .../inlineSuspendOfNoinlineSuspend.kt | 1 - .../codegen/boxInline/suspend/returnValue.kt | 2 - .../crossingCoroutineBoundaries.kt | 2 - .../suspend/stateMachine/independentInline.kt | 2 - .../innerLambdaWithoutCrossinline.kt | 1 - .../suspend/stateMachine/innerObject.kt | 2 - .../innerObjectWithoutCapturingCrossinline.kt | 2 - .../suspend/stateMachine/insideObject.kt | 2 - .../suspend/stateMachine/normalInline.kt | 2 - .../stateMachine/objectInsideLambdas.kt | 2 - .../suspend/tryCatchStackTransform.kt | 2 - .../suspensionPointInMonitor/output.txt | 4 +- 55 files changed, 680 insertions(+), 366 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation_ir.txt 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 fcfe41aa36d..684805b3b69 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.codegen.coroutines import com.intellij.util.ArrayUtil +import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CalculatedClosure @@ -17,6 +18,7 @@ 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 import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.* @@ -32,6 +34,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature @@ -470,8 +473,9 @@ class CoroutineCodegenForLambda private constructor( val stateMachineBuilder = CoroutineTransformerMethodVisitor( mv, access, name, desc, null, null, obtainClassBuilderForCoroutineState = { v }, - element = element, - diagnostics = state.diagnostics, + reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(element, state, it) }, + lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0, + sourceFile = element.containingKtFile.name, shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = v.thisName, isForNamedFunction = false, @@ -768,3 +772,7 @@ private object FailingFunctionGenerationStrategy : FunctionGenerationStrategy() error("This functions must not be called") } } + +fun reportSuspensionPointInsideMonitor(element: KtElement, state: GenerationState, stackTraceElement: String) { + state.diagnostics.report(ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR.on(element, stackTraceElement)) +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index 8d3e993dfe6..52c38d6afd8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -60,13 +60,13 @@ class CoroutineTransformerMethodVisitor( private val isForNamedFunction: Boolean, private val shouldPreserveClassInitialization: Boolean, private val languageVersionSettings: LanguageVersionSettings, - // These two are needed to report diagnostics about suspension points inside critical section - private val element: KtElement, - private val diagnostics: DiagnosticSink, // Since tail-call optimization of functions with Unit return type relies on ability of call-site to recognize them, // in order to ignore return value and push Unit, when we cannot ensure this ability, for example, when the function overrides function, // returning Any, we need to disable tail-call optimization for these functions. private val disableTailCallOptimizationForFunctionReturningUnit: Boolean, + private val reportSuspensionPointInsideMonitor: (String) -> Unit, + private val lineNumber: Int, + private val sourceFile: String, // It's only matters for named functions, may differ from '!isStatic(access)' in case of DefaultImpls private val needDispatchReceiver: Boolean = false, // May differ from containingClassInternalName in case of DefaultImpls @@ -76,8 +76,6 @@ class CoroutineTransformerMethodVisitor( ) : TransformationMethodVisitor(delegate, access, name, desc, signature, exceptions) { private val classBuilderForCoroutineState: ClassBuilder by lazy(obtainClassBuilderForCoroutineState) - private val lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0 - private val sourceFile = element.containingKtFile.name private var continuationIndex = if (isForNamedFunction) -1 else 0 private var dataIndex = if (isForNamedFunction) -1 else 1 @@ -315,7 +313,7 @@ class CoroutineTransformerMethodVisitor( sourceFile, findSuspensionPointLineNumber(suspensionPoint)?.line ?: -1 ) - diagnostics.report(ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR.on(element, "$stackTraceElement")) + reportSuspensionPointInsideMonitor("$stackTraceElement") return } } 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 e8ff4783de7..e561b11b4b7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.codegen.coroutines +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 @@ -96,8 +97,9 @@ open class SuspendFunctionGenerationStrategy( return CoroutineTransformerMethodVisitor( mv, access, name, desc, null, null, containingClassInternalName, this::classBuilderForCoroutineState, isForNamedFunction = true, - element = declaration, - diagnostics = state.diagnostics, + reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(declaration, state, it) }, + lineNumber = CodegenUtil.getLineNumberForElement(declaration, false) ?: 0, + sourceFile = declaration.containingKtFile.name, shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization, needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null, internalNameForDispatchReceiver = containingClassInternalNameOrNull(), 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 9b470f5bb51..33a539b3390 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -302,7 +302,8 @@ class AnonymousObjectTransformer( sourceNode.name, if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc, inliningContext.callSiteInfo.isInlineOrInsideInline, - isSuspendFunctionOrLambda(sourceNode) + isSuspendFunctionOrLambda(sourceNode), + inliningContext.root.sourceCompilerForInline.inlineCallSiteInfo.lineNumber ), null ) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCallSiteInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCallSiteInfo.kt index 3516d01de69..e6b461249d0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCallSiteInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCallSiteInfo.kt @@ -10,5 +10,6 @@ class InlineCallSiteInfo( val functionName: String?, val functionDesc: String?, val isInlineOrInsideInline: Boolean, - val isSuspend: Boolean + val isSuspend: Boolean, + val lineNumber: Int ) \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index 257eeedec5b..3d7bd951cb7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -157,6 +157,7 @@ class MethodInliner( ), AsmTypeRemapper(remapper, result) ) + val fakeContinuationName = CoroutineTransformer.findFakeContinuationConstructorClassName(node) val markerShift = calcMarkerShift(parameters, node) val lambdaInliner = object : InlineAdapter(remappingMethodAdapter, parameters.argsSizeOnStack, sourceMapper) { private var transformationInfo: TransformationInfo? = null @@ -176,9 +177,7 @@ class MethodInliner( inlineCallSiteInfo ) val transformer = transformationInfo!!.createTransformer( - childInliningContext, - isSameModule, - CoroutineTransformer.findFakeContinuationConstructorClassName(node) + childInliningContext, isSameModule, fakeContinuationName ) val transformResult = transformer.doTransform(nodeRemapper) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt index 2e22b940c52..d7bd9dff72c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt @@ -75,6 +75,8 @@ interface SourceCompilerForInline { val compilationContextFunctionDescriptor: FunctionDescriptor fun getContextLabels(): Set + + fun reportSuspensionPointInsideMonitor(stackTraceElement: String) } @@ -120,7 +122,8 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid signature.asmMethod.name, signature.asmMethod.descriptor, compilationContextFunctionDescriptor.isInlineOrInsideInline(), - compilationContextFunctionDescriptor.isSuspend + compilationContextFunctionDescriptor.isSuspend, + CodegenUtil.getLineNumberForElement(callElement, false) ?: 0 ) } @@ -365,6 +368,10 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid ) } + override fun reportSuspensionPointInsideMonitor(stackTraceElement: String) { + org.jetbrains.kotlin.codegen.coroutines.reportSuspensionPointInsideMonitor(callElement, state, stackTraceElement) + } + companion object { fun getContext( descriptor: DeclarationDescriptor, 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 103f4aa0a8c..531f92e7857 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 @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.codegen.inline.coroutines import com.intellij.util.ArrayUtil +import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.codegen.AsmUtil.CAPTURED_THIS_FIELD import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.TransformationMethodVisitor @@ -66,29 +67,20 @@ class CoroutineTransformer( if (state.languageVersionSettings.isReleaseCoroutines()) superClassName.endsWith("ContinuationImpl") else methods.any { it.name == "getLabel" } - private fun crossinlineLambda(): PsiExpressionLambda? = inliningContext.expressionMap.values.find { - it is PsiExpressionLambda && it.isCrossInline - }?.cast() - private fun isStateMachine(node: MethodNode): Boolean = node.instructions.asSequence().any { insn -> insn is LdcInsnNode && insn.cst == ILLEGAL_STATE_ERROR_MESSAGE } private fun isSuspendLambda(node: MethodNode) = isResumeImpl(node) fun newMethod(node: MethodNode): DeferredMethodVisitor { - // Find ANY element to report error about suspension point in monitor on. - val element = crossinlineLambda()?.functionWithBodyOrCallableReference - ?: inliningContext.root.sourceCompilerForInline.callElement as? KtElement - ?: error("crossinline lambda should have element") - return when { isResumeImpl(node) -> { assert(!isStateMachine(node)) { "Inlining/transforming state-machine" } - newStateMachineForLambda(node, element) + newStateMachineForLambda(node) } - isSuspendFunctionWithFakeConstructorCall(node) -> newStateMachineForNamedFunction(node, element) + isSuspendFunctionWithFakeConstructorCall(node) -> newStateMachineForNamedFunction(node) else -> error("no need to generate state maching for ${node.name}") } } @@ -99,7 +91,7 @@ class CoroutineTransformer( private fun isSuspendFunctionWithFakeConstructorCall(node: MethodNode): Boolean = findFakeContinuationConstructorClassName(node) != null - private fun newStateMachineForLambda(node: MethodNode, element: KtElement): DeferredMethodVisitor { + private fun newStateMachineForLambda(node: MethodNode): DeferredMethodVisitor { val name = node.name.removeSuffix(FOR_INLINE_SUFFIX) return DeferredMethodVisitor( MethodNode( @@ -107,13 +99,16 @@ class CoroutineTransformer( ArrayUtil.toStringArray(node.exceptions) ) ) { + val sourceCompilerForInline = inliningContext.root.sourceCompilerForInline val stateMachineBuilder = surroundNoinlineCallsWithMarkers( node, CoroutineTransformerMethodVisitor( createNewMethodFrom(node, name), node.access, name, node.desc, null, null, obtainClassBuilderForCoroutineState = { classBuilder }, - element = element, - diagnostics = state.diagnostics, + reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) }, + // TODO: this linenumbers might not be correct and since they are used only for step-over, check them. + lineNumber = sourceCompilerForInline.inlineCallSiteInfo.lineNumber, + sourceFile = sourceCompilerForInline.callsiteFile?.name ?: "", languageVersionSettings = state.languageVersionSettings, shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = classBuilder.thisName, @@ -137,7 +132,7 @@ class CoroutineTransformer( } } - private fun newStateMachineForNamedFunction(node: MethodNode, element: KtElement): DeferredMethodVisitor { + private fun newStateMachineForNamedFunction(node: MethodNode): DeferredMethodVisitor { val name = node.name.removeSuffix(FOR_INLINE_SUFFIX) val continuationClassName = findFakeContinuationConstructorClassName(node) assert(inliningContext is RegeneratedClassContext) @@ -149,20 +144,23 @@ class CoroutineTransformer( ) { // If the node already has state-machine, it is safer to generate state-machine. val disableTailCallOptimization = methods.find { it.name == name && it.desc == node.desc }?.let { isStateMachine(it) } ?: false + val sourceCompilerForInline = inliningContext.root.sourceCompilerForInline val stateMachineBuilder = surroundNoinlineCallsWithMarkers( node, CoroutineTransformerMethodVisitor( createNewMethodFrom(node, name), node.access, name, node.desc, null, null, obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! }, - element = element, - diagnostics = state.diagnostics, + reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) }, + lineNumber = sourceCompilerForInline.inlineCallSiteInfo.lineNumber, + sourceFile = sourceCompilerForInline.callsiteFile?.name ?: "", languageVersionSettings = state.languageVersionSettings, shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = classBuilder.thisName, isForNamedFunction = true, needDispatchReceiver = true, internalNameForDispatchReceiver = classBuilder.thisName, - disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization + disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization, + putContinuationParameterToLvt = !state.isIrBackend ) ) @@ -233,7 +231,7 @@ class CoroutineTransformer( fun oldContinuationFrom(method: MethodNode): String? = methods.find { it.name == method.name + FOR_INLINE_SUFFIX && it.desc == method.desc } - ?.let { findFakeContinuationConstructorClassName(it) } + ?.let { findFakeContinuationConstructorClassName(it) } companion object { fun findFakeContinuationConstructorClassName(node: MethodNode): String? { 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 ba16c86568a..3942c9df8c1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -431,7 +431,7 @@ fun addSuspendMarker(v: InstructionAdapter, isStartNotEnd: Boolean) { v.emitInlineMarker(if (isStartNotEnd) INLINE_MARKER_BEFORE_SUSPEND_ID else INLINE_MARKER_AFTER_SUSPEND_ID) } -internal fun addFakeContinuationConstructorCallMarker(v: InstructionAdapter, isStartNotEnd: Boolean) { +fun addFakeContinuationConstructorCallMarker(v: InstructionAdapter, isStartNotEnd: Boolean) { v.emitInlineMarker(if (isStartNotEnd) INLINE_MARKER_BEFORE_FAKE_CONTINUATION_CONSTRUCTOR_CALL else INLINE_MARKER_AFTER_FAKE_CONTINUATION_CONSTRUCTOR_CALL) } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt index cf1b2de8fc6..ea51853a355 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt @@ -83,6 +83,7 @@ abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid() protected val currentScope get() = scopeStack.peek() protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2] protected val allScopes get() = scopeStack + protected val currentDeclarationParent get() = allScopes.last { it.irElement is IrDeclarationParent }.irElement as IrDeclarationParent fun printScopeStack() { scopeStack.forEach { println(it.scope.scopeOwner) } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index 4fa4dc02460..9fcd54c2cb9 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.common.ir import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor import org.jetbrains.kotlin.backend.common.deepCopyWithVariables +import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities @@ -566,9 +567,17 @@ fun copyBodyToStatic(oldFunction: IrFunction, staticFunction: IrFunction) { val mapping: Map = (listOfNotNull(oldFunction.dispatchReceiverParameter, oldFunction.extensionReceiverParameter) + oldFunction.valueParameters) .zip(staticFunction.valueParameters).toMap() - staticFunction.body = oldFunction.body + copyBodyWithParametersMapping(staticFunction, oldFunction, mapping) +} + +fun copyBodyWithParametersMapping( + newFunction: IrFunction, + oldFunction: IrFunction, + mapping: Map +) { + newFunction.body = oldFunction.body?.deepCopyWithSymbols(oldFunction) ?.transform( - object: IrElementTransformerVoid() { + object : IrElementTransformerVoid() { // Remap return targets to the static method so they do not appear to be // non-local returns. override fun visitReturn(expression: IrReturn): IrExpression { @@ -578,8 +587,9 @@ fun copyBodyToStatic(oldFunction: IrFunction, staticFunction: IrFunction) { expression.startOffset, expression.endOffset, expression.type, - staticFunction.symbol, - expression.value) + newFunction.symbol, + expression.value + ) } else expression } @@ -589,8 +599,9 @@ fun copyBodyToStatic(oldFunction: IrFunction, staticFunction: IrFunction) { IrGetValueImpl(expression.startOffset, expression.endOffset, it.type, it.symbol, expression.origin) } ?: expression - }, null) - ?.patchDeclarationParents(staticFunction) + }, null + ) + ?.patchDeclarationParents(newFunction) } val IrSymbol.isSuspend: Boolean diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index 364901d2c75..e58d57f098a 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -87,6 +87,9 @@ class LocalDeclarationsLowering( object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE : IrDeclarationOriginImpl("FIELD_FOR_CAPTURED_VALUE", isSynthetic = true) + object DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE : + IrDeclarationOriginImpl("FIELD_FOR_CROSSINLINE_CAPTURED_VALUE", isSynthetic = true) + private object STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE : IrStatementOriginImpl("INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE") @@ -655,14 +658,15 @@ class LocalDeclarationsLowering( name: Name, visibility: Visibility, parent: IrClass, - fieldType: IrType + fieldType: IrType, + isCrossinline: Boolean ): IrField { val descriptor = WrappedFieldDescriptor() val symbol = IrFieldSymbolImpl(descriptor) return IrFieldImpl( startOffset, endOffset, - DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE, + if (isCrossinline) DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE else DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE, symbol, name, fieldType, @@ -682,16 +686,18 @@ class LocalDeclarationsLowering( val generatedNames = mutableSetOf() localClassContext.closure.capturedValues.forEach { capturedValue -> + val owner = capturedValue.owner val irField = createFieldForCapturedValue( classDeclaration.startOffset, classDeclaration.endOffset, - suggestNameForCapturedValue(capturedValue.owner, generatedNames), + suggestNameForCapturedValue(owner, generatedNames), Visibilities.PRIVATE, classDeclaration, - capturedValue.owner.type + owner.type, + owner is IrValueParameter && owner.isCrossinline ) - localClassContext.capturedValueToField[capturedValue.owner] = irField + localClassContext.capturedValueToField[owner] = irField } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/declarations/declarationBuilders.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/declarations/declarationBuilders.kt index 43917ad4e99..9628c2ca87c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/declarations/declarationBuilders.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/declarations/declarationBuilders.kt @@ -176,13 +176,15 @@ fun IrDeclarationContainer.addFunction( returnType: IrType, modality: Modality = Modality.FINAL, isStatic: Boolean = false, - isSuspend: Boolean = false + isSuspend: Boolean = false, + origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED ): IrSimpleFunction = addFunction { this.name = Name.identifier(name) this.returnType = returnType this.modality = modality this.isSuspend = isSuspend + this.origin = origin }.apply { if (!isStatic) { dispatchReceiverParameter = parentAsClass.thisReceiver!!.copyTo(this) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt index 8c7d470d1f6..60130b08bb0 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 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.backend.jvm @@ -51,4 +40,9 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { object POLYMORPHIC_SIGNATURE_INSTANTIATION : IrDeclarationOriginImpl("POLYMORPHIC_SIGNATURE_INSTANTIATION", isSynthetic = true) object ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER : IrDeclarationOriginImpl("ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER", isSynthetic = true) object OBJECT_SUPER_CONSTRUCTOR_PARAMETER : IrDeclarationOriginImpl("OBJECT_SUPER_CONSTURCTOR_PARAMETER", isSynthetic = true) + object CONTINUATION_CLASS : IrDeclarationOriginImpl("CONTINUATION_CLASS") + object SUSPEND_LAMBDA : IrDeclarationOriginImpl("SUSPEND_LAMBDA") + object FOR_INLINE_STATE_MACHINE_TEMPLATE : IrDeclarationOriginImpl("FOR_INLINE_TEMPLATE") + object FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE : IrDeclarationOriginImpl("FOR_INLINE_TEMPLATE_CROSSINLINE") + object FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW : IrDeclarationOriginImpl("FOR_INLINE_TEMPLATE_CROSSINLINE_VIEW") } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index 139c27dd1c4..146ba20b872 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.ir.builders.irNull import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrFunctionReference import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.SymbolTable @@ -97,9 +98,8 @@ class JvmBackendContext( override val internalPackageFqn = FqName("kotlin.jvm") - val suspendFunctionContinuations = mutableMapOf() - val suspendLambdaToOriginalFunctionMap = mutableMapOf() - val continuationClassBuilders = mutableMapOf() + val suspendLambdaToOriginalFunctionMap = mutableMapOf() + val continuationClassBuilders = mutableMapOf() val suspendFunctionOriginalToView = mutableMapOf() val suspendFunctionViewToOriginal = mutableMapOf() val fakeContinuation: IrExpression = createFakeContinuation(this) 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 c339ff1d0c3..6d2a8f09959 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 @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField import org.jetbrains.kotlin.backend.jvm.lower.hasAssertionsDisabledField @@ -126,12 +127,6 @@ open class ClassCodegen protected constructor( } else null } - // Suspend function state-machine builder requires half-built continuation class - val continuationCodegens = nestedClasses.filter { it.irClass in context.suspendFunctionContinuations.values } - for (continuationCodegen in continuationCodegens) { - continuationCodegen.generate() - } - val fileEntry = context.psiSourceManager.getFileEntry(irClass.fileParent) if (fileEntry != null) { /* TODO: Temporary workaround: ClassBuilder needs a pathless name. */ @@ -153,14 +148,14 @@ open class ClassCodegen protected constructor( // Generate nested classes at the end, to ensure that codegen for companion object will have the necessary JVM signatures in its // trace for properties moved to the outer class - for (codegen in (nestedClasses - continuationCodegens)) { + for (codegen in nestedClasses) { codegen.generate() } generateKotlinMetadataAnnotation() - if (irClass in context.suspendFunctionContinuations.values) { - context.continuationClassBuilders[irClass] = visitor + if (irClass.origin == JvmLoweredDeclarationOrigin.CONTINUATION_CLASS) { + context.continuationClassBuilders[irClass.attributeOwnerId as IrSimpleFunction] = visitor } else { done() } 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 a17c1f04954..0b67e684761 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 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen +import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom import org.jetbrains.kotlin.backend.common.ir.isSuspend @@ -14,6 +15,8 @@ import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME +import org.jetbrains.kotlin.codegen.coroutines.reportSuspensionPointInsideMonitor +import org.jetbrains.kotlin.codegen.inline.addFakeContinuationConstructorCallMarker import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET @@ -37,11 +40,14 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource 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.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter internal fun generateStateMachineForNamedFunction( irFunction: IrFunction, @@ -49,21 +55,19 @@ internal fun generateStateMachineForNamedFunction( methodVisitor: MethodVisitor, access: Int, signature: JvmMethodGenericSignature, - continuationClassBuilder: ClassBuilder?, + obtainContinuationClassBuilder: () -> ClassBuilder, element: KtElement ): MethodVisitor { assert(irFunction.isSuspend) - assert(continuationClassBuilder != null) { - "Class builder for continuation is null" - } val state = classCodegen.state val languageVersionSettings = state.languageVersionSettings assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" } return CoroutineTransformerMethodVisitor( - methodVisitor, access, signature.asmMethod.name, signature.asmMethod.descriptor, signature.genericsSignature, null, - obtainClassBuilderForCoroutineState = { continuationClassBuilder!! }, - element = element, - diagnostics = state.diagnostics, + methodVisitor, access, signature.asmMethod.name, signature.asmMethod.descriptor, null, null, + obtainClassBuilderForCoroutineState = obtainContinuationClassBuilder, + reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(element, state, it) }, + lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0, + sourceFile = classCodegen.irClass.file.name, languageVersionSettings = languageVersionSettings, shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = classCodegen.visitor.thisName, @@ -92,8 +96,9 @@ internal fun generateStateMachineForLambda( return CoroutineTransformerMethodVisitor( methodVisitor, access, signature.asmMethod.name, signature.asmMethod.descriptor, signature.genericsSignature, null, obtainClassBuilderForCoroutineState = { classCodegen.visitor }, - element = element, - diagnostics = state.diagnostics, + reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(element, state, it) }, + lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0, + sourceFile = classCodegen.irClass.file.name, languageVersionSettings = languageVersionSettings, shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = classCodegen.visitor.thisName, @@ -102,17 +107,18 @@ internal fun generateStateMachineForLambda( ) } -internal fun IrFunction.isInvokeSuspendOfLambda(context: JvmBackendContext): Boolean = - name.asString() == INVOKE_SUSPEND_METHOD_NAME && parent in context.suspendLambdaToOriginalFunctionMap +internal fun IrFunction.isInvokeSuspendOfLambda(): Boolean = + name.asString() == INVOKE_SUSPEND_METHOD_NAME && parentAsClass.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA -internal fun IrFunction.isInvokeOfSuspendLambda(context: JvmBackendContext): Boolean = - name.asString() == "invoke" && parent in context.suspendLambdaToOriginalFunctionMap +internal fun IrFunction.isInvokeSuspendForInlineOfLambda(): Boolean = + origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE + && parentAsClass.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA -internal fun IrFunction.isInvokeSuspendOfContinuation(context: JvmBackendContext): Boolean = - name.asString() == INVOKE_SUSPEND_METHOD_NAME && parentAsClass in context.suspendFunctionContinuations.values +internal fun IrFunction.isInvokeSuspendOfContinuation(): Boolean = + name.asString() == INVOKE_SUSPEND_METHOD_NAME && parentAsClass.origin == JvmLoweredDeclarationOrigin.CONTINUATION_CLASS internal fun IrFunction.isInvokeOfSuspendCallableReference(): Boolean = isSuspend && name.asString() == "invoke" && - (parent as? IrClass)?.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL + parentAsClass.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL internal fun IrFunction.isKnownToBeTailCall(): Boolean = when (origin) { @@ -126,13 +132,15 @@ internal fun IrFunction.isKnownToBeTailCall(): Boolean = else -> isInvokeOfSuspendCallableReference() } -internal fun IrFunction.shouldNotContainSuspendMarkers(context: JvmBackendContext): Boolean = - isInvokeSuspendOfContinuation(context) || isKnownToBeTailCall() +internal fun IrFunction.shouldNotContainSuspendMarkers(): Boolean = + isInvokeSuspendOfContinuation() || isKnownToBeTailCall() // Transform `suspend fun foo(params): RetType` into `fun foo(params, $completion: Continuation): Any?` // the result is called 'view', just to be consistent with old backend. internal fun IrFunction.getOrCreateSuspendFunctionViewIfNeeded(context: JvmBackendContext): IrFunction { - if (!isSuspend || origin == JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW) return this + if (!isSuspend || origin == JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW || + origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW + ) return this context.suspendFunctionOriginalToView[this]?.let { return it } return suspendFunctionView(context) } @@ -152,7 +160,12 @@ private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFuncti else WrappedSimpleFunctionDescriptor(sourceElement = originalDescriptor.source) return IrFunctionImpl( - startOffset, endOffset, JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW, IrSimpleFunctionSymbolImpl(descriptor), + startOffset, endOffset, + if (origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE) + JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW + else + JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW, + IrSimpleFunctionSymbolImpl(descriptor), name, visibility, modality, context.irBuiltIns.anyNType, isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect, isFakeOverride = false, isOperator = false @@ -196,6 +209,7 @@ private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFuncti return super.visitCall(expression.createSuspendFunctionCallViewIfNeeded(context, it, callerIsInlineLambda = false)) } }) + it.copyAttributes(this) } } @@ -216,7 +230,8 @@ internal fun IrCall.createSuspendFunctionCallViewIfNeeded( } val continuationParameter = when { - caller.isInvokeSuspendOfLambda(context) || caller.isInvokeSuspendOfContinuation(context) -> + caller.isInvokeSuspendOfLambda() || caller.isInvokeSuspendOfContinuation() || + caller.isInvokeSuspendForInlineOfLambda() -> IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, caller.dispatchReceiverParameter!!.symbol) callerIsInlineLambda -> context.fakeContinuation else -> IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, caller.valueParameters.last().symbol) @@ -231,3 +246,31 @@ internal fun createFakeContinuation(context: JvmBackendContext): IrExpression = context.ir.symbols.continuationClass.createType(true, listOf(makeTypeProjection(context.irBuiltIns.anyNType, Variance.INVARIANT))), "FAKE_CONTINUATION" ) + +internal fun generateFakeContinuationConstructorCall( + v: InstructionAdapter, + containingClassBuilder: ClassBuilder, + classBuilder: ClassBuilder, + irFunction: IrFunction +) { + val continuationType = Type.getObjectType(classBuilder.thisName) + // TODO: This is different in case of DefaultImpls + val thisNameType = Type.getObjectType(containingClassBuilder.thisName.replace(".", "/")) + val continuationIndex = listOfNotNull(irFunction.dispatchReceiverParameter, irFunction.extensionReceiverParameter).size + + irFunction.valueParameters.size - 1 + with(v) { + addFakeContinuationConstructorCallMarker(this, true) + anew(continuationType) + dup() + if (irFunction.dispatchReceiverParameter != null) { + load(0, AsmTypes.OBJECT_TYPE) + load(continuationIndex, Type.getObjectType("kotlin/coroutines/Continuation")) + invokespecial(continuationType.internalName, "", "(${thisNameType}Lkotlin/coroutines/Continuation;)V", false) + } else { + load(continuationIndex, Type.getObjectType("kotlin/coroutines/Continuation")) + invokespecial(continuationType.internalName, "", "(Lkotlin/coroutines/Continuation;)V", false) + } + pop() + addFakeContinuationConstructorCallMarker(this, false) + } +} \ No newline at end of file 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 b9f23331cc4..d137314fa36 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 @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.putNeedClassReificationMarker import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.AS import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.SAFE_AS +import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump @@ -48,9 +49,11 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.model.TypeParameterMarker +import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.keysToMap +import org.jetbrains.kotlin.utils.sure import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -193,6 +196,7 @@ class ExpressionCodegen( val info = BlockInfo() val body = irFunction.body!! generateNonNullAssertions() + generateFakeContinuationConstructorIfNeeded() val result = body.accept(this, info) // If this function has an expression body, return the result of that expression. // Otherwise, if it does not end in a return statement, it must be void-returning, @@ -213,6 +217,19 @@ class ExpressionCodegen( writeParameterInLocalVariableTable(startLabel, endLabel) } + private fun generateFakeContinuationConstructorIfNeeded() { + if (irFunction.origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW) return + val continuationClass = classCodegen.irClass.functions.find { + it.name.asString() == irFunction.name.asString().removeSuffix(FOR_INLINE_SUFFIX) + }?.body?.statements?.get(0) ?: error("could not find continuation for ${irFunction.render()}") + generateFakeContinuationConstructorCall( + mv, + classCodegen.visitor, + context.continuationClassBuilders[(continuationClass as IrClass).attributeOwnerId]!!, + irFunction + ) + } + private fun generateNonNullAssertions() { if (state.isParamAssertionsDisabled) return @@ -229,14 +246,17 @@ class ExpressionCodegen( irFunction.origin == IrDeclarationOrigin.BRIDGE_SPECIAL || irFunction.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE || irFunction.origin == JvmLoweredDeclarationOrigin.JVM_STATIC_WRAPPER || - irFunction.origin == JvmLoweredDeclarationOrigin.MULTIFILE_BRIDGE + irFunction.origin == JvmLoweredDeclarationOrigin.MULTIFILE_BRIDGE || + irFunction.parentAsClass.origin == JvmLoweredDeclarationOrigin.CONTINUATION_CLASS || + irFunction.parentAsClass.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA if (notCallableFromJava) return // Do not generate non-null checks for suspend function views. When resumed the arguments // will be null and the actual values are taken from the continuation. - val isSuspendFunctionView = irFunction.origin == JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW + val isSuspendFunctionView = irFunction.origin == JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW || + irFunction.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW if (isSuspendFunctionView) return @@ -381,7 +401,7 @@ class ExpressionCodegen( } expression.symbol.descriptor is ConstructorDescriptor -> throw AssertionError("IrCall with ConstructorDescriptor: ${expression.javaClass.simpleName}") - callee.isSuspend && !irFunction.shouldNotContainSuspendMarkers(classCodegen.context) -> + callee.isSuspend && !irFunction.shouldNotContainSuspendMarkers() -> addInlineMarker(mv, isStartNotEnd = true) } @@ -407,13 +427,13 @@ class ExpressionCodegen( expression.markLineNumber(true) // Do not generate redundant markers in continuation class. - if (callee.isSuspend && !irFunction.shouldNotContainSuspendMarkers(classCodegen.context)) { + if (callee.isSuspend && !irFunction.shouldNotContainSuspendMarkers()) { addSuspendMarker(mv, isStartNotEnd = true) } callGenerator.genCall(callable, this, expression) - if (callee.isSuspend && !irFunction.shouldNotContainSuspendMarkers(classCodegen.context)) { + if (callee.isSuspend && !irFunction.shouldNotContainSuspendMarkers()) { addSuspendMarker(mv, isStartNotEnd = false) addInlineMarker(mv, isStartNotEnd = false) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index d52e1bb9688..cd59d547bb5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -12,6 +12,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.mangleNameIfNeeded import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.codegen.ClassBuilderMode +import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_IMPL_NAME_SUFFIX import org.jetbrains.kotlin.codegen.visitAnnotableParameterCount import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.Modality @@ -28,6 +30,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature 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.commons.InstructionAdapter @@ -77,34 +80,56 @@ open class FunctionCodegen( generateAnnotationDefaultValueIfNeeded(methodVisitor) } else { val frameMap = createFrameMapWithReceivers() - val irClass = context.suspendFunctionContinuations[irFunction] - val element = (irFunction.symbol.descriptor.psiElement - ?: context.suspendLambdaToOriginalFunctionMap[irFunction.parent]?.symbol?.descriptor?.psiElement) as? KtElement - val continuationClassBuilder = context.continuationClassBuilders[irClass] methodVisitor = when { - irFunction.isSuspend && - // We do not generate continuation and state-machine for synthetic accessors, bridges, and delegated members, - // in a sense, they are tail-call - !irFunction.isKnownToBeTailCall() && - // TODO: We should generate two versions of inline suspend function: one with state-machine and one without - !irFunction.isInline -> + irFunction.hasContinuation() -> { generateStateMachineForNamedFunction( - irFunction, classCodegen, methodVisitor, flags, signature, continuationClassBuilder, element!! + irFunction, classCodegen, methodVisitor, + access = flags, + signature = signature, + obtainContinuationClassBuilder = { + context.continuationClassBuilders[continuationClass().attributeOwnerId]!! + }, + element = psiElement() ) - irFunction.isInvokeSuspendOfLambda(context) -> generateStateMachineForLambda( - classCodegen, methodVisitor, flags, signature, element!! + } + irFunction.isInvokeSuspendOfLambda() -> generateStateMachineForLambda( + classCodegen, methodVisitor, flags, signature, psiElement() ) else -> methodVisitor } ExpressionCodegen(functionView, signature, frameMap, InstructionAdapter(methodVisitor), classCodegen, inlinedInto).generate() methodVisitor.visitMaxs(-1, -1) - continuationClassBuilder?.done() + if (irFunction.hasContinuation()) { + context.continuationClassBuilders[continuationClass().attributeOwnerId].sure { + "Could not find continuation class builder for ${continuationClass().render()}" + }.done() + } } methodVisitor.visitEnd() return signature } + private fun psiElement(): KtElement = + if (irFunction.isSuspend) irFunction.symbol.descriptor.psiElement as KtElement + else context.suspendLambdaToOriginalFunctionMap[irFunction.parentAsClass.attributeOwnerId]!!.symbol.descriptor.psiElement as KtElement + + private fun IrFunction.hasContinuation(): Boolean = isSuspend && + // We do not generate continuation and state-machine for synthetic accessors, bridges, and delegated members, + // in a sense, they are tail-call + !isKnownToBeTailCall() && + // TODO: We should generate two versions of inline suspend function: one with state-machine and one without + !isInline && + // This is suspend lambda parameter of inline function + origin != IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA && + // This is just a template for inliner + origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE && + // Continuations are generated for suspendImpls + parentAsClass.functions.none { it.name.asString() == name.asString() + SUSPEND_IMPL_NAME_SUFFIX } + + private fun continuationClass(): IrClass = + irFunction.body!!.statements[0] as IrClass + private fun calculateMethodFlags(isStatic: Boolean): Int { if (irFunction.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) { return Opcodes.ACC_PUBLIC or Opcodes.ACC_SYNTHETIC.let { 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 c720bc5d4be..6dbfa9a84dd 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 @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.codegen import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.codegen.BaseExpressionCodegen import org.jetbrains.kotlin.codegen.ClassBuilder @@ -16,16 +17,24 @@ import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression +import org.jetbrains.kotlin.ir.util.isSuspend +import org.jetbrains.kotlin.ir.util.nameForIrSerialization +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.Method @@ -61,7 +70,8 @@ class IrSourceCompilerForInline( root.signature.asmMethod.descriptor, //compilationContextFunctionDescriptor.isInlineOrInsideInline() false, - compilationContextFunctionDescriptor.isSuspend + compilationContextFunctionDescriptor.isSuspend, + findElement()?.let { CodegenUtil.getLineNumberForElement(it, false) } ?: 0 ) } @@ -127,13 +137,20 @@ class IrSourceCompilerForInline( override fun getContextLabels(): Set { val name = codegen.irFunction.name.asString() if (name == INVOKE_SUSPEND_METHOD_NAME) { - codegen.context.suspendLambdaToOriginalFunctionMap[codegen.irFunction.parent]?.let { + codegen.context.suspendLambdaToOriginalFunctionMap[codegen.irFunction.parentAsClass.attributeOwnerId]?.let { return setOf(it.name.asString()) } } return setOf(name) } + // TODO: Find a way to avoid using PSI here + override fun reportSuspensionPointInsideMonitor(stackTraceElement: String) { + org.jetbrains.kotlin.codegen.coroutines.reportSuspensionPointInsideMonitor(findElement()!!, state, stackTraceElement) + } + + private fun findElement() = (callElement.symbol.descriptor.original as? DeclarationDescriptorWithSource)?.source?.getPsi() as? KtElement + internal val isPrimaryCopy: Boolean get() = codegen.classCodegen !is FakeClassCodegen diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt index dc2b5330356..737da7a6671 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrPackageFragment +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrTypeParameter import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* @@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.types.impl.originalKotlinType import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.isSuspendFunction +import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.load.kotlin.computeExpandedTypeForInlineClass import org.jetbrains.kotlin.load.kotlin.mapBuiltInType diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt index 277839842e1..4078b63dc23 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt @@ -5,12 +5,14 @@ package org.jetbrains.kotlin.backend.jvm.codegen +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Label @@ -90,7 +92,8 @@ fun PromisedValue.coerce(target: Type, irTarget: IrType): PromisedValue { // Boxing and unboxing kotlin.Result leads to CCE in generated code val doNotCoerceKotlinResultInContinuation = - (codegen.irFunction.isInvokeSuspendOfContinuation(codegen.context) || codegen.irFunction.isInvokeOfSuspendLambda(codegen.context)) + (codegen.irFunction.parentAsClass.origin == JvmLoweredDeclarationOrigin.CONTINUATION_CLASS || + codegen.irFunction.parentAsClass.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA) && (irType.isKotlinResult() || irTarget.isKotlinResult()) // Coerce inline classes diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt index b1baed41934..5e9b54469ed 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt @@ -5,19 +5,16 @@ package org.jetbrains.kotlin.backend.jvm.lower -import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName +import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.ir.* +import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase -import org.jetbrains.kotlin.backend.common.pop -import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrBlock -import org.jetbrains.kotlin.backend.jvm.codegen.isInvokeOfSuspendCallableReference import org.jetbrains.kotlin.codegen.coroutines.* +import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement @@ -43,7 +40,6 @@ import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.util.OperatorNameConventions -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance internal val addContinuationPhase = makeIrFilePhase( ::AddContinuationLowering, @@ -51,50 +47,53 @@ internal val addContinuationPhase = makeIrFilePhase( "Add continuation classes to suspend functions and transform suspend lambdas into continuations" ) -private object CONTINUATION_CLASS : IrDeclarationOriginImpl("CONTINUATION_CLASS") - private class AddContinuationLowering(private val context: JvmBackendContext) : FileLoweringPass { + private val functionsToAdd = mutableMapOf>() + override fun lower(irFile: IrFile) { - val suspendLambdas = markSuspendLambdas(irFile) - val suspendFunctions = markSuspendFunctions(irFile, suspendLambdas.map { it.function }.toSet()) - for (lambda in suspendLambdas) { - generateContinuationClassForLambda(lambda) + val (suspendLambdas, inlineLambdas) = markSuspendLambdas(irFile) + transformSuspendFunctions(irFile, (suspendLambdas.map { it.function } + inlineLambdas).toSet()) + for ((clazz, functions) in functionsToAdd) { + for (function in functions) { + clazz.declarations.add(function) + } } transformReferencesToSuspendLambdas(irFile, suspendLambdas) - transformSuspendCalls(irFile) - for (suspendFunction in suspendFunctions) { - generateContinuationClassForNamedFunction(suspendFunction) - } } private fun transformReferencesToSuspendLambdas(irFile: IrFile, suspendLambdas: List) { - irFile.transformChildrenVoid(object : IrElementTransformerVoid() { + for (lambda in suspendLambdas) { + (lambda.function.parent as IrDeclarationContainer).declarations.remove(lambda.function) + } + irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { - expression.transformChildrenVoid(this) - if (!expression.isSuspend) return expression - val constructor = suspendLambdas.singleOrNull { it.function == expression.symbol.owner }?.constructor - ?: return expression - val expressionArguments = expression.getArguments().map { it.second } - assert(constructor.valueParameters.size == expressionArguments.size) { - "Inconsistency between callable reference to suspend lambda and the corresponding continuation" - } - val irBuilder = context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset) - irBuilder.run { - return irCall(constructor.symbol).apply { - expressionArguments.forEachIndexed { index, argument -> - putValueArgument(index, argument) + val info = suspendLambdas.singleOrNull { it.function == expression.symbol.owner } ?: return expression + return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).run { + val expressionArguments = expression.getArguments().map { it.second } + irBlock { + +generateContinuationClassForLambda(info, currentDeclarationParent) + val constructor = info.constructor + assert(constructor.valueParameters.size == expressionArguments.size + 1) { + "Inconsistency between callable reference to suspend lambda and the corresponding continuation" + } + +irCall(constructor.symbol).apply { + expressionArguments.forEachIndexed { index, argument -> + putValueArgument(index, argument) + } + // Pass null as completion parameter + putValueArgument(expressionArguments.size, irNull()) } } - } + }.also { it.transformChildrenVoid(this) } } }) } - private fun generateContinuationClassForLambda(info: SuspendLambdaInfo) { + private fun generateContinuationClassForLambda(info: SuspendLambdaInfo, parent: IrDeclarationParent): IrClass { val suspendLambda = context.ir.symbols.suspendLambdaClass.owner - suspendLambda.createContinuationClassFor(info.function).apply { + return suspendLambda.createContinuationClassFor(parent, JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA).apply { copyAttributes(info.reference) val functionNClass = context.ir.symbols.getJvmFunctionClass(info.arity + 1) superTypes.add( @@ -120,11 +119,14 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : .mapNotNull { (i, field) -> if (info.reference.getValueArgument(i) == null) field else null } val parametersWithArguments = parametersFields - parametersWithoutArguments val constructor = addPrimaryConstructorForLambda(info.arity, info.reference, parametersFields) - val secondaryConstructor = addSecondaryConstructorForLambda(constructor) val invokeToOverride = functionNClass.functions.single { it.owner.valueParameters.size == info.arity + 1 && it.owner.name.asString() == "invoke" } val invokeSuspend = addInvokeSuspendForLambda(info.function, parametersFields, receiverField) + if (info.capturesCrossinline) { + addInvokeSuspendForInlineForLambda(invokeSuspend, info.function, parametersFields, receiverField) + } + info.function.parentAsClass.declarations.remove(info.function) if (info.arity <= 1) { val singleParameterField = receiverField ?: parametersWithoutArguments.singleOrNull() val create = addCreate(constructor, suspendLambda, info, parametersWithArguments, singleParameterField) @@ -139,9 +141,9 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : ) } - context.suspendLambdaToOriginalFunctionMap[this] = info.function + context.suspendLambdaToOriginalFunctionMap[attributeOwnerId as IrFunctionReference] = info.function - info.constructor = secondaryConstructor + info.constructor = constructor } } @@ -154,46 +156,73 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : it.owner.name.asString() == INVOKE_SUSPEND_METHOD_NAME && it.owner.valueParameters.size == 1 && it.owner.valueParameters[0].type.isKotlinResult() }.owner - return addFunctionOverride(superMethod) - .also { function -> - function.copyTypeParametersFrom(irFunction) - function.body = irFunction.body?.deepCopyWithSymbols(function) - function.body?.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitGetValue(expression: IrGetValue): IrExpression { - if (expression.symbol.owner == irFunction.extensionReceiverParameter) { - assert(receiverField != null) - return IrGetFieldImpl( - expression.startOffset, - expression.endOffset, - receiverField!!.symbol, - receiverField.type - ).also { - it.receiver = - IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.dispatchReceiverParameter!!.symbol) - } - } else if (expression.symbol.owner == irFunction.dispatchReceiverParameter) { - return IrGetValueImpl(expression.startOffset, expression.endOffset, function.dispatchReceiverParameter!!.symbol) - } - val field = fields.find { it.name == expression.symbol.owner.name } ?: return expression - return IrGetFieldImpl(expression.startOffset, expression.endOffset, field.symbol, field.type).also { - it.receiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.dispatchReceiverParameter!!.symbol) - } - } + return addFunctionOverride(superMethod).also { it.copySuspendLambdaBodyFrom(irFunction, receiverField, fields) } + } - // If the suspend lambda body contains declarations of other classes (for other lambdas), - // do not rewrite those. In particular, that could lead to rewriting of returns in nested - // lambdas to unintended non-local returns. - override fun visitClass(declaration: IrClass): IrStatement { - return declaration - } + private fun IrClass.addInvokeSuspendForInlineForLambda( + invokeSuspend: IrFunction, + irFunction: IrFunction, + fields: List, + receiverField: IrField? + ): IrFunction { + return addFunction( + INVOKE_SUSPEND_METHOD_NAME + FOR_INLINE_SUFFIX, + context.irBuiltIns.anyNType, + Modality.FINAL, + origin = JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE + ).apply { + invokeSuspend.valueParameters.mapTo(valueParameters) { it.copyTo(this) } + }.also { it.copySuspendLambdaBodyFrom(irFunction, receiverField, fields) } + } - override fun visitReturn(expression: IrReturn): IrExpression { - val ret = super.visitReturn(expression) as IrReturn - return IrReturnImpl(ret.startOffset, ret.endOffset, ret.type, function.symbol, ret.value) + private fun IrSimpleFunction.copySuspendLambdaBodyFrom( + irFunction: IrFunction, + receiverField: IrField?, + fields: List + ) { + copyTypeParametersFrom(irFunction) + body = irFunction.body?.deepCopyWithSymbols(this) + body?.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitGetValue(expression: IrGetValue): IrExpression { + if (expression.symbol.owner == irFunction.extensionReceiverParameter) { + assert(receiverField != null) + return IrGetFieldImpl( + expression.startOffset, + expression.endOffset, + receiverField!!.symbol, + receiverField.type + ).also { + it.receiver = + IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter!!.symbol) } - }) - (irFunction.parent as IrDeclarationContainer).declarations.remove(irFunction) + } else if (expression.symbol.owner == irFunction.dispatchReceiverParameter) { + return IrGetValueImpl(expression.startOffset, expression.endOffset, dispatchReceiverParameter!!.symbol) + } + val field = fields.find { it.name == expression.symbol.owner.name } ?: return expression + return IrGetFieldImpl(expression.startOffset, expression.endOffset, field.symbol, field.type).also { + it.receiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter!!.symbol) + } } + + // If the suspend lambda body contains declarations of other classes (for other lambdas), + // do not rewrite those. In particular, that could lead to rewriting of returns in nested + // lambdas to unintended non-local returns. + override fun visitClass(declaration: IrClass): IrStatement { + return declaration + } + + override fun visitReturn(expression: IrReturn): IrExpression { + val ret = super.visitReturn(expression) as IrReturn + return IrReturnImpl(ret.startOffset, ret.endOffset, ret.type, symbol, ret.value) + } + }) + } + + private fun IrFunction.copyBodyFrom(oldFunction: IrFunction) { + val mapping: Map = + (listOfNotNull(oldFunction.dispatchReceiverParameter, oldFunction.extensionReceiverParameter) + oldFunction.valueParameters) + .zip(listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).toMap() + copyBodyWithParametersMapping(this, oldFunction, mapping) } private fun IrDeclarationContainer.addFunctionOverride( @@ -311,17 +340,15 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : } } - private fun IrClass.createContinuationClassFor(irFunction: IrFunction): IrClass = buildClass { - name = "${irFunction.name}\$Continuation".synthesizedName - origin = CONTINUATION_CLASS + private fun IrClass.createContinuationClassFor(parent: IrDeclarationParent, newOrigin: IrDeclarationOrigin): IrClass = buildClass { + name = Name.special("") + origin = newOrigin visibility = JavaVisibilities.PACKAGE_VISIBILITY }.also { irClass -> irClass.createImplicitParameterDeclarationWithWrappedDescriptor() irClass.superTypes.add(defaultType) - val parent = irFunction.parents.firstIsInstance() irClass.parent = parent - parent.declarations.add(irClass) } // Primary constructor accepts parameters equal to function reference arguments + continuation and sets the fields. @@ -354,51 +381,37 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : } } - // Secondary constructor accepts parameters equals to arguments of function reference and is used for callable references - // TODO: get rid of it and use primary constructor only - private fun IrClass.addSecondaryConstructorForLambda(primary: IrConstructor): IrConstructor = - addConstructor { - isPrimary = false - returnType = defaultType - }.also { constructor -> - constructor.valueParameters.addAll(primary.valueParameters.dropLast(1).map { it.copyTo(constructor) }) - - constructor.body = context.createIrBuilder(constructor.symbol).irBlockBody { - +irDelegatingConstructorCall(primary).also { - for ((index, param) in constructor.valueParameters.withIndex()) { - it.putValueArgument(index, irGet(param)) - } - it.putValueArgument(constructor.valueParameters.size, irNull()) - } - } - } - private fun IrFunction.addCompletionValueParameter(): IrValueParameter = addValueParameter(SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME, continuationType()) private fun IrFunction.continuationType(): IrType = context.ir.symbols.continuationClass.typeWith(returnType).makeNullable() - private fun generateContinuationClassForNamedFunction(irFunction: IrFunction) { - context.ir.symbols.continuationImplClass.owner.createContinuationClassFor(irFunction).apply { - val resultField = addField( - context.state.languageVersionSettings.dataFieldName(), - context.irBuiltIns.anyType, - JavaVisibilities.PACKAGE_VISIBILITY - ) - val capturedThisField = irFunction.dispatchReceiverParameter?.let { addField("this\$0", it.type) } - val labelField = addField(COROUTINE_LABEL_FIELD_NAME, context.irBuiltIns.intType, JavaVisibilities.PACKAGE_VISIBILITY) - addConstructorForNamedFunction(capturedThisField) - var function = irFunction - if (function is IrSimpleFunction && function.isOverridable && function.body != null) { - // Create static method for the suspend state machine method so that reentering the method - // does not lead to virtual dispatch to the wrong method. - context.suspendFunctionContinuations[function] = this - function = createStaticSuspendImpl(function) + private fun generateContinuationClassForNamedFunction( + irFunction: IrFunction, + dispatchReceiverParameter: IrValueParameter?, + attributeContainer: IrAttributeContainer + ): IrClass { + return context.ir.symbols.continuationImplClass.owner + .createContinuationClassFor(irFunction, JvmLoweredDeclarationOrigin.CONTINUATION_CLASS) + .apply { + val resultField = addField( + context.state.languageVersionSettings.dataFieldName(), + context.irBuiltIns.anyType, + JavaVisibilities.PACKAGE_VISIBILITY + ) + val capturedThisField = dispatchReceiverParameter?.let { addField("this\$0", it.type) } + val labelField = addField(COROUTINE_LABEL_FIELD_NAME, context.irBuiltIns.intType, JavaVisibilities.PACKAGE_VISIBILITY) + addConstructorForNamedFunction(capturedThisField) + addInvokeSuspendForNamedFunction( + irFunction, + resultField, + labelField, + capturedThisField, + irFunction.origin == JvmLoweredDeclarationOrigin.SUSPEND_IMPL_STATIC_FUNCTION + ) + copyAttributes(attributeContainer) } - addInvokeSuspendForNamedFunction(function, resultField, labelField, capturedThisField, function != irFunction) - context.suspendFunctionContinuations[function] = this - } } private fun IrClass.addConstructorForNamedFunction(capturedThisField: IrField?): IrConstructor = addConstructor { @@ -433,7 +446,8 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : capturedThisField: IrField?, isStaticSuspendImpl: Boolean ) { - val invokeSuspend = context.ir.symbols.continuationImplClass.owner.functions.single { it.name == Name.identifier(INVOKE_SUSPEND_METHOD_NAME) } + val invokeSuspend = context.ir.symbols.continuationImplClass.owner.functions + .single { it.name == Name.identifier(INVOKE_SUSPEND_METHOD_NAME) } addFunctionOverride(invokeSuspend).also { function -> function.body = context.createIrBuilder(function.symbol).irBlockBody { +irSetField(irGet(function.dispatchReceiverParameter!!), resultField, irGet(function.valueParameters[0])) @@ -495,7 +509,6 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : copyMetadata = false ) copyBodyToStatic(irFunction, static) - (irFunction.parent as IrClass).declarations.add(static) // Rewrite the body of the original suspend method to forward to the new static method. irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody { +irReturn(irCall(static).also { @@ -521,30 +534,78 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : } // TODO: Generate two copies of inline suspend functions - private fun markSuspendFunctions(irFile: IrFile, suspendLambdas: Set): Set { - val result = hashSetOf() + private fun transformSuspendFunctions(irFile: IrFile, suspendAndInlineLambdas: Set) { + irFile.transformChildrenVoid(object : IrElementTransformerVoid() { + private val functionsStack = arrayListOf() + private val suspendFunctionsCapturingCrossinline = mutableSetOf() - irFile.acceptChildrenVoid(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) + override fun visitFunction(declaration: IrFunction): IrStatement { + functionsStack.push(declaration) + val function = super.visitFunction(declaration) as IrFunction + functionsStack.pop() + if (skip(function)) return function + + function as IrSimpleFunction + if (function in suspendFunctionsCapturingCrossinline) { + val newFunction = buildFun { + name = Name.identifier(function.name.asString() + FOR_INLINE_SUFFIX) + returnType = function.returnType + modality = function.modality + isSuspend = function.isSuspend + origin = JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE + }.apply { + dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this) + extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(this) + function.valueParameters.mapTo(valueParameters) { it.copyTo(this) } + copyBodyFrom(function) + copyAttributes(function) + } + functionsToAdd[function.parentAsClass] = mutableSetOf(newFunction) + } + + val newFunction = if (function.isOverridable) { + // Create static method for the suspend state machine method so that reentering the method + // does not lead to virtual dispatch to the wrong method. + functionsToAdd.getOrPut(function.parentAsClass) { mutableSetOf() }.add(function) + createStaticSuspendImpl(function) + } else function + + newFunction.body = context.createIrBuilder(newFunction.symbol).irBlockBody { + +generateContinuationClassForNamedFunction( + newFunction, + function.dispatchReceiverParameter, + declaration as IrAttributeContainer + ) + for (statement in newFunction.body!!.statements) { + +statement + } + } + return newFunction } - override fun visitFunction(declaration: IrFunction) { - super.visitFunction(declaration) - if (declaration.isSuspend && declaration !in suspendLambdas && !declaration.isInline && - !declaration.isInvokeOfSuspendCallableReference() + private fun skip(function: IrFunction) = + !function.isSuspend || function in suspendAndInlineLambdas || function.isInline || function.body == null || + function.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE || + function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || + function.parentAsClass.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL + + override fun visitFieldAccess(expression: IrFieldAccessExpression): IrExpression { + val result = super.visitFieldAccess(expression) + val function = functionsStack.peek() ?: return result + if (function.isSuspend && + expression.symbol.owner.origin == LocalDeclarationsLowering.DECLARATION_ORIGIN_FIELD_FOR_CROSSINLINE_CAPTURED_VALUE ) { - result.add(declaration) + suspendFunctionsCapturingCrossinline += function } + return result } }) - - return result } - private fun markSuspendLambdas(irElement: IrElement): List { + private fun markSuspendLambdas(irElement: IrElement): Pair, List> { val suspendLambdas = arrayListOf() val inlineLambdas = mutableSetOf() + val capturesCrossinline = mutableSetOf() irElement.acceptChildrenVoid(object : IrElementVisitorVoid { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) @@ -552,6 +613,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : override fun visitCall(expression: IrCall) { val owner = expression.symbol.owner + // Collect inline lambdas if (owner.isInline) { for (i in 0 until expression.valueArgumentsCount) { if (owner.valueParameters[i].isNoinline) continue @@ -565,6 +627,20 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : } } } + // collect lambdas, which capture crossinline + for (i in 0 until expression.valueArgumentsCount) { + val valueArgument = expression.getValueArgument(i) as? IrBlock ?: continue + if (valueArgument.origin != IrStatementOrigin.LAMBDA) continue + val reference = valueArgument.statements.last() as? IrFunctionReference ?: continue + for (j in 0 until reference.valueArgumentsCount) { + val getValue = (reference.getValueArgument(j) as? IrGetValue) ?: continue + val parameter = getValue.symbol.owner as? IrValueParameter ?: continue + if (parameter.isCrossinline) { + capturesCrossinline += reference + break + } + } + } expression.acceptChildrenVoid(this) } @@ -575,32 +651,21 @@ private class AddContinuationLowering(private val context: JvmBackendContext) : suspendLambdas += SuspendLambdaInfo( expression.symbol.owner, (expression.type as IrSimpleType).arguments.size - 1, - expression + expression, + expression in capturesCrossinline ) } } }) - return suspendLambdas + return suspendLambdas to inlineLambdas.map { it.symbol.owner } } - private fun transformSuspendCalls(irFile: IrFile) { - irFile.transformChildrenVoid(object : IrElementTransformerVoid() { - private val functionStack = mutableListOf() - override fun visitElement(element: IrElement): IrElement { - element.transformChildrenVoid(this) - return element - } - - override fun visitFunction(declaration: IrFunction): IrStatement { - functionStack.push(declaration) - val res = super.visitFunction(declaration) - functionStack.pop() - return res - } - }) - } - - private class SuspendLambdaInfo(val function: IrFunction, val arity: Int, val reference: IrFunctionReference) { + private class SuspendLambdaInfo( + val function: IrFunction, + val arity: Int, + val reference: IrFunctionReference, + val capturesCrossinline: Boolean + ) { lateinit var constructor: IrConstructor } } \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index 43d3c78c2b7..3703b51ad47 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -414,7 +414,4 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) } } } - - private val currentDeclarationParent - get() = allScopes.last { it.irElement is IrDeclarationParent }.irElement as IrDeclarationParent } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt index 6fdac531a5c..4abcf024f7b 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/FunctionGenerator.kt @@ -56,10 +56,6 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio ?.let { declareSimpleFunctionInner(it, ktElement, IrDeclarationOrigin.FAKE_OVERRIDE).buildWithScope { irFunction -> generateFunctionParameterDeclarationsAndReturnType(irFunction, ktElement, null) - val overridenSymbol = irFunction.overriddenSymbols.first() - if (overridenSymbol.isBound) { - irFunction.copyAttributes(overridenSymbol.owner) - } } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt index c8edc52d3b2..54c580fa9ab 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt @@ -8,10 +8,7 @@ package org.jetbrains.kotlin.ir.declarations.lazy import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibility -import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.declarations.IrTypeParameter +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator diff --git a/compiler/testData/codegen/box/coroutines/bridges/lambdaWithLongReceiver_ir.txt b/compiler/testData/codegen/box/coroutines/bridges/lambdaWithLongReceiver_ir.txt index dc6c2b7df54..159b90bc0a6 100644 --- a/compiler/testData/codegen/box/coroutines/bridges/lambdaWithLongReceiver_ir.txt +++ b/compiler/testData/codegen/box/coroutines/bridges/lambdaWithLongReceiver_ir.txt @@ -1,18 +1,10 @@ -@kotlin.Metadata -final class LambdaWithLongReceiverKt$$call$Continuation { - field label: int - @org.jetbrains.annotations.NotNull field result: java.lang.Object - public method (@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): void - public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object -} - @kotlin.coroutines.jvm.internal.DebugMetadata @kotlin.Metadata final class LambdaWithLongReceiverKt$box$1$1 { private field $p: long private field label: int + inner class LambdaWithLongReceiverKt$box$1 inner class LambdaWithLongReceiverKt$box$1$1 - public method (): void public method (@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): void public final @org.jetbrains.annotations.NotNull method create(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): kotlin.coroutines.Continuation public final method invoke(p0: java.lang.Object, p1: java.lang.Object): java.lang.Object @@ -26,17 +18,24 @@ final class LambdaWithLongReceiverKt$box$1 { field L$0: java.lang.Object private field label: int inner class LambdaWithLongReceiverKt$box$1 - public method (@org.jetbrains.annotations.NotNull p0: kotlin.jvm.internal.Ref$ObjectRef): void + inner class LambdaWithLongReceiverKt$box$1$1 public method (@org.jetbrains.annotations.NotNull p0: kotlin.jvm.internal.Ref$ObjectRef, @org.jetbrains.annotations.Nullable p1: 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 +final class LambdaWithLongReceiverKt$call$1 { + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + public method (@org.jetbrains.annotations.Nullable p0: 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 LambdaWithLongReceiverKt { inner class LambdaWithLongReceiverKt$box$1 - inner class LambdaWithLongReceiverKt$box$1$1 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 call(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object diff --git a/compiler/testData/codegen/box/coroutines/bridges/lambdaWithMultipleParameters_ir.txt b/compiler/testData/codegen/box/coroutines/bridges/lambdaWithMultipleParameters_ir.txt index 6bfc5717d49..320a45d2a85 100644 --- a/compiler/testData/codegen/box/coroutines/bridges/lambdaWithMultipleParameters_ir.txt +++ b/compiler/testData/codegen/box/coroutines/bridges/lambdaWithMultipleParameters_ir.txt @@ -1,11 +1,3 @@ -@kotlin.Metadata -final class LambdaWithMultipleParametersKt$$call$Continuation { - field label: int - @org.jetbrains.annotations.NotNull field result: java.lang.Object - public method (@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): void - public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object -} - @kotlin.coroutines.jvm.internal.DebugMetadata @kotlin.Metadata final class LambdaWithMultipleParametersKt$box$1$1 { @@ -16,8 +8,8 @@ final class LambdaWithMultipleParametersKt$box$1$1 { private field e: long private field f: long private field label: int + inner class LambdaWithMultipleParametersKt$box$1 inner class LambdaWithMultipleParametersKt$box$1$1 - public method (): void public method (@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): void public final method invoke(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object, p4: java.lang.Object, p5: java.lang.Object, p6: 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 @@ -30,17 +22,24 @@ final class LambdaWithMultipleParametersKt$box$1 { field L$0: java.lang.Object private field label: int inner class LambdaWithMultipleParametersKt$box$1 - public method (@org.jetbrains.annotations.NotNull p0: kotlin.jvm.internal.Ref$ObjectRef): void + inner class LambdaWithMultipleParametersKt$box$1$1 public method (@org.jetbrains.annotations.NotNull p0: kotlin.jvm.internal.Ref$ObjectRef, @org.jetbrains.annotations.Nullable p1: 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 +final class LambdaWithMultipleParametersKt$call$1 { + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + public method (@org.jetbrains.annotations.Nullable p0: 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 LambdaWithMultipleParametersKt { inner class LambdaWithMultipleParametersKt$box$1 - inner class LambdaWithMultipleParametersKt$box$1$1 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 call(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function7, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object diff --git a/compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt b/compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt index 46cc46e4ba6..331bd111f62 100644 --- a/compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt +++ b/compiler/testData/codegen/box/coroutines/inlineGenericFunCalledFromSubclass.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JVM_IR // WITH_RUNTIME // WITH_COROUTINES // WITH_REFLECT diff --git a/compiler/testData/codegen/box/coroutines/multiModule/inlineWithJava.kt b/compiler/testData/codegen/box/coroutines/multiModule/inlineWithJava.kt index a375c5bcc97..aa7c820ff98 100644 --- a/compiler/testData/codegen/box/coroutines/multiModule/inlineWithJava.kt +++ b/compiler/testData/codegen/box/coroutines/multiModule/inlineWithJava.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_COROUTINES // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithoutStateMachine_ir.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithoutStateMachine_ir.txt index e4a3ea16085..f3fa064975e 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithoutStateMachine_ir.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithoutStateMachine_ir.txt @@ -1,24 +1,3 @@ -@kotlin.Metadata -@kotlin.coroutines.jvm.internal.DebugMetadata -final class InlineWithoutStateMachineKt$$complexSuspend$Continuation { - field L$0: java.lang.Object - field L$1: java.lang.Object - field label: int - @org.jetbrains.annotations.NotNull field result: java.lang.Object - public method (@org.jetbrains.annotations.Nullable p0: 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 -@kotlin.coroutines.jvm.internal.DebugMetadata -final class InlineWithoutStateMachineKt$$suspendHere$Continuation { - field L$0: java.lang.Object - field label: int - @org.jetbrains.annotations.NotNull field result: java.lang.Object - public method (@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): void - public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object -} - @kotlin.coroutines.jvm.internal.DebugMetadata @kotlin.Metadata final class InlineWithoutStateMachineKt$box$1 { @@ -27,13 +6,33 @@ final class InlineWithoutStateMachineKt$box$1 { field L$1: java.lang.Object private field label: int inner class InlineWithoutStateMachineKt$box$1 - public method (@org.jetbrains.annotations.NotNull p0: kotlin.jvm.internal.Ref$ObjectRef): void public method (@org.jetbrains.annotations.NotNull p0: kotlin.jvm.internal.Ref$ObjectRef, @org.jetbrains.annotations.Nullable p1: 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 InlineWithoutStateMachineKt$complexSuspend$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + public method (@org.jetbrains.annotations.Nullable p0: 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 +@kotlin.coroutines.jvm.internal.DebugMetadata +final class InlineWithoutStateMachineKt$suspendHere$1 { + field L$0: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + public method (@org.jetbrains.annotations.Nullable p0: 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 InlineWithoutStateMachineKt { inner class InlineWithoutStateMachineKt$box$1 diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.kt index 6b79d996018..d407e0f35e2 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JVM_IR // COMMON_COROUTINES_TEST // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation_ir.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation_ir.txt new file mode 100644 index 00000000000..49b02cf8b6b --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/innerObjectRetransformation_ir.txt @@ -0,0 +1,170 @@ +@kotlin.Metadata +public interface flow/Flow { + public abstract @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +public interface flow/FlowCollector { + public abstract @org.jetbrains.annotations.Nullable method emit(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.coroutines.jvm.internal.DebugMetadata +@kotlin.Metadata +final class flow/InnerObjectRetransformationKt$box$1 { + private field label: int + inner class flow/InnerObjectRetransformationKt$box$1 + public method (@org.jetbrains.annotations.Nullable 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 +public final class flow/InnerObjectRetransformationKt$check$$inlined$collect$1 { + inner class flow/InnerObjectRetransformationKt$check$$inlined$collect$1 + public method (): void + public @org.jetbrains.annotations.Nullable method emit(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata +final class flow/InnerObjectRetransformationKt$check$$inlined$flow$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + synthetic final field this$0: flow.InnerObjectRetransformationKt$check$$inlined$flow$1 + public method (p0: flow.InnerObjectRetransformationKt$check$$inlined$flow$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 flow/InnerObjectRetransformationKt$check$$inlined$flow$1 { + inner class flow/InnerObjectRetransformationKt$check$$inlined$flow$1 + public method (): void + public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +final class flow/InnerObjectRetransformationKt$check$$inlined$flowWith$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + synthetic final field this$0: flow.InnerObjectRetransformationKt$check$$inlined$flowWith$1 + public method (p0: flow.InnerObjectRetransformationKt$check$$inlined$flowWith$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 flow/InnerObjectRetransformationKt$check$$inlined$flowWith$1 { + synthetic final field $this$flowWith$inlined: flow.Flow + inner class flow/InnerObjectRetransformationKt$check$$inlined$flowWith$1 + public method (p0: flow.Flow): void + public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata +final class flow/InnerObjectRetransformationKt$check$1 { + field L$0: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + public method (@org.jetbrains.annotations.Nullable p0: 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 +final class flow/InnerObjectRetransformationKt$collect$2$emit$1 { + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + private field this$0: flow.InnerObjectRetransformationKt$collect$2 + public method (@org.jetbrains.annotations.NotNull p0: flow.InnerObjectRetransformationKt$collect$2, @org.jetbrains.annotations.Nullable 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 flow/InnerObjectRetransformationKt$collect$2 { + private synthetic final field $action: kotlin.jvm.functions.Function2 + inner class flow/InnerObjectRetransformationKt$collect$2 + public method (p0: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method emit$$forInline(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object + public @org.jetbrains.annotations.Nullable method emit(@org.jetbrains.annotations.NotNull p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +final class flow/InnerObjectRetransformationKt$flow$1$collect$1 { + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + private field this$0: flow.InnerObjectRetransformationKt$flow$1 + public method (@org.jetbrains.annotations.NotNull p0: flow.InnerObjectRetransformationKt$flow$1, @org.jetbrains.annotations.Nullable 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 flow/InnerObjectRetransformationKt$flow$1 { + private synthetic final field $block: kotlin.jvm.functions.Function2 + inner class flow/InnerObjectRetransformationKt$flow$1 + public method (p0: kotlin.jvm.functions.Function2): void + public @org.jetbrains.annotations.Nullable method collect$$forInline(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object + public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata +final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + synthetic final field this$0: flow.InnerObjectRetransformationKt$flowWith$$inlined$flow$1 + public method (p0: flow.InnerObjectRetransformationKt$flowWith$$inlined$flow$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 flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1 { + synthetic final field $builderBlock$inlined: kotlin.jvm.functions.Function2 + synthetic final field $this$flowWith$inlined: flow.Flow + inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$1 + public method (p0: kotlin.jvm.functions.Function2, p1: flow.Flow): void + public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +@kotlin.coroutines.jvm.internal.DebugMetadata +final class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + field L$2: java.lang.Object + field label: int + @org.jetbrains.annotations.NotNull field result: java.lang.Object + synthetic final field this$0: flow.InnerObjectRetransformationKt$flowWith$$inlined$flow$2 + public method (p0: flow.InnerObjectRetransformationKt$flowWith$$inlined$flow$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 flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2 { + synthetic final field $builderBlock$inlined: kotlin.jvm.functions.Function2 + synthetic final field $this$flowWith$inlined: flow.Flow + inner class flow/InnerObjectRetransformationKt$flowWith$$inlined$flow$2 + public method (p0: kotlin.jvm.functions.Function2, p1: flow.Flow): void + public @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.FlowCollector, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.Continuation): java.lang.Object +} + +@kotlin.Metadata +public final class flow/InnerObjectRetransformationKt { + inner class flow/InnerObjectRetransformationKt$box$1 + inner class flow/InnerObjectRetransformationKt$collect$2 + inner class flow/InnerObjectRetransformationKt$flow$1 + 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 check(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object + private final static @org.jetbrains.annotations.Nullable method collect(@org.jetbrains.annotations.NotNull p0: flow.Flow, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function2, @org.jetbrains.annotations.NotNull p2: kotlin.coroutines.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.NotNull method flow(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2): flow.Flow + public final static @org.jetbrains.annotations.NotNull method flowWith(@org.jetbrains.annotations.NotNull p0: flow.Flow, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function2): flow.Flow +} diff --git a/compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt b/compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt index 94ec07a05ef..a5075cb2728 100644 --- a/compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt +++ b/compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt b/compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt index cf8cbb6854b..5e59d373816 100644 --- a/compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt +++ b/compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt @@ -1,5 +1,4 @@ // IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // TARGET_BACKEND: JVM // FILE: flow.kt // COMMON_COROUTINES_TEST diff --git a/compiler/testData/codegen/boxInline/suspend/fileNameInMetadata.kt b/compiler/testData/codegen/boxInline/suspend/fileNameInMetadata.kt index 467c3cc7025..1d2b33952bf 100644 --- a/compiler/testData/codegen/boxInline/suspend/fileNameInMetadata.kt +++ b/compiler/testData/codegen/boxInline/suspend/fileNameInMetadata.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfCrossinlineSuspend.kt b/compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfCrossinlineSuspend.kt index 4740a726a49..15a4f9e48d1 100644 --- a/compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfCrossinlineSuspend.kt +++ b/compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfCrossinlineSuspend.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfNoinlineSuspend.kt b/compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfNoinlineSuspend.kt index 10dd86715e4..c7fc5f17467 100644 --- a/compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfNoinlineSuspend.kt +++ b/compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfNoinlineSuspend.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineOrdinary.kt b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineOrdinary.kt index 7ffcb18c176..40ea9b34541 100644 --- a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineOrdinary.kt +++ b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineOrdinary.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineSuspend.kt b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineSuspend.kt index 01536d7acbf..8d4f7be1c72 100644 --- a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineSuspend.kt +++ b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineSuspend.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineOrdinary.kt b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineOrdinary.kt index 296c88fc2d8..a0d25fba8ae 100644 --- a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineOrdinary.kt +++ b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineOrdinary.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineSuspend.kt b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineSuspend.kt index a63a082ae19..c57caf2dea6 100644 --- a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineSuspend.kt +++ b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineSuspend.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfOrdinary.kt b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfOrdinary.kt index 1b66cdc2bea..a1032fc5ded 100644 --- a/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfOrdinary.kt +++ b/compiler/testData/codegen/boxInline/suspend/inlineSuspendOfOrdinary.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt b/compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt index 66b84ca197a..60fd00b16dd 100644 --- a/compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt +++ b/compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST diff --git a/compiler/testData/codegen/boxInline/suspend/returnValue.kt b/compiler/testData/codegen/boxInline/suspend/returnValue.kt index db06204b7b3..dab4fe03b0d 100644 --- a/compiler/testData/codegen/boxInline/suspend/returnValue.kt +++ b/compiler/testData/codegen/boxInline/suspend/returnValue.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: inlined.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt index 494850f622a..84af03aaa19 100644 --- a/compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/crossingCoroutineBoundaries.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // COMMON_COROUTINES_TEST // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt index 874677645e6..60b882c4d27 100644 --- a/compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/independentInline.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // COMMON_COROUTINES_TEST // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaWithoutCrossinline.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaWithoutCrossinline.kt index ba795db77ef..6edf3d7c16c 100644 --- a/compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaWithoutCrossinline.kt +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaWithoutCrossinline.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: inlined.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/innerObject.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/innerObject.kt index 1ff60db78a2..1de655b1392 100644 --- a/compiler/testData/codegen/boxInline/suspend/stateMachine/innerObject.kt +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/innerObject.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: inlined.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectWithoutCapturingCrossinline.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectWithoutCapturingCrossinline.kt index c94416c134a..e2b36fb44f7 100644 --- a/compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectWithoutCapturingCrossinline.kt +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectWithoutCapturingCrossinline.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: inlined.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/insideObject.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/insideObject.kt index 3da6ab6b624..96d88510c28 100644 --- a/compiler/testData/codegen/boxInline/suspend/stateMachine/insideObject.kt +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/insideObject.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // COMMON_COROUTINES_TEST // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/normalInline.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/normalInline.kt index c0354d720a5..fe9b071115e 100644 --- a/compiler/testData/codegen/boxInline/suspend/stateMachine/normalInline.kt +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/normalInline.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: inlined.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/codegen/boxInline/suspend/stateMachine/objectInsideLambdas.kt b/compiler/testData/codegen/boxInline/suspend/stateMachine/objectInsideLambdas.kt index 9b4b42bf03d..7f7855a0873 100644 --- a/compiler/testData/codegen/boxInline/suspend/stateMachine/objectInsideLambdas.kt +++ b/compiler/testData/codegen/boxInline/suspend/stateMachine/objectInsideLambdas.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // COMMON_COROUTINES_TEST // WITH_RUNTIME // WITH_COROUTINES diff --git a/compiler/testData/codegen/boxInline/suspend/tryCatchStackTransform.kt b/compiler/testData/codegen/boxInline/suspend/tryCatchStackTransform.kt index cfd556ccbed..dde11dccd53 100644 --- a/compiler/testData/codegen/boxInline/suspend/tryCatchStackTransform.kt +++ b/compiler/testData/codegen/boxInline/suspend/tryCatchStackTransform.kt @@ -1,5 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: inlined.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/output.txt index 996d7a58f1a..59cb54abe15 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/output.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/output.txt @@ -4,9 +4,9 @@ compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/so compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/source.kt:14:13: error: a suspension point at SourceKt$test$2.invokeSuspend(source.kt:17) is inside a critical section builder { ^ -compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/source.kt:24:25: error: a suspension point at SourceKt$test$3$invokeSuspend$$inlined$withCrossinline$2.invokeSuspend(source.kt:62) is inside a critical section +compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/source.kt:24:9: error: a suspension point at SourceKt$test$3$invokeSuspend$$inlined$withCrossinline$2.invokeSuspend(source.kt:62) is inside a critical section withCrossinline { - ^ + ^ compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/source.kt:50:34: error: a suspension point at SourceKt$withCrossinline$c$1.invokeSuspend(source.kt:52) is inside a critical section val c : suspend () -> Unit = { ^