diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index 43c80b70f71..d0d6e25a12c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -8,11 +8,9 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.psi.PsiElement import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive -import org.jetbrains.kotlin.codegen.context.ClosureContext import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.renderer.DescriptorRenderer -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature @@ -41,21 +39,6 @@ abstract class InlineCodegen( protected var maskStartIndex = -1 protected var methodHandleInDefaultMethodIndex = -1 - protected fun throwCompilationException( - nodeAndSmap: SMAPAndMethodNode?, e: Exception, generateNodeText: Boolean - ): CompilationException { - val contextDescriptor = sourceCompiler.compilationContextDescriptor - val element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor) - val node = nodeAndSmap?.node - throw CompilationException( - "Couldn't inline method call '${jvmSignature.asmMethod}' into\n" + - DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" + - (element?.text ?: "") + - if (generateNodeText) "\nCause: " + node.nodeText else "", - e, sourceCompiler.callElement as? PsiElement - ) - } - protected fun generateStub(text: String, codegen: BaseExpressionCodegen) { leaveTemps() AsmUtil.genThrow(codegen.visitor, "java/lang/UnsupportedOperationException", "Call is part of inline cycle: $text") @@ -75,9 +58,15 @@ abstract class InlineCodegen( } catch (e: CompilationException) { throw e } catch (e: InlineException) { - throw throwCompilationException(nodeAndSmap, e, false) + throw CompilationException( + "Couldn't inline method call: ${sourceCompiler.callElementText}", + e, sourceCompiler.callElement as? PsiElement + ) } catch (e: Exception) { - throw throwCompilationException(nodeAndSmap, e, true) + throw CompilationException( + "Couldn't inline method call: ${sourceCompiler.callElementText}\nMethod: ${nodeAndSmap?.node?.nodeText}", + e, sourceCompiler.callElement as? PsiElement + ) } } @@ -119,21 +108,6 @@ abstract class InlineCodegen( return true } - private fun continuationValue(): StackValue { - assert(codegen is ExpressionCodegen) { "Expected ExpressionCodegen in coroutineContext inlining" } - codegen as ExpressionCodegen - - val parentContext = codegen.context.parentContext - return if (parentContext is ClosureContext) { - val originalSuspendLambdaDescriptor = - parentContext.originalSuspendLambdaDescriptor ?: error("No original lambda descriptor found") - codegen.genCoroutineInstanceForSuspendLambda(originalSuspendLambdaDescriptor) - ?: error("No stack value for coroutine instance of lambda found") - } else - codegen.getContinuationParameterFromEnclosingSuspendFunctionDescriptor(codegen.context.functionDescriptor) - ?: error("No stack value for continuation parameter of suspend function") - } - protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) { val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index) closureInfo.functionalArgument = lambdaInfo 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 f27c4f21f98..8ff78548c02 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer -import org.jetbrains.kotlin.codegen.inline.coroutines.isSuspendLambdaCapturedByOuterObjectOrLambda import org.jetbrains.kotlin.codegen.inline.coroutines.markNoinlineLambdaIfSuspend import org.jetbrains.kotlin.codegen.inline.coroutines.surroundInvokesWithSuspendMarkersIfNeeded import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer @@ -24,7 +23,6 @@ import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNot import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.load.java.JvmAbi -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.kotlin.utils.SmartList @@ -230,7 +228,7 @@ class MethodInliner( return } - val nullableAnyType = inliningContext.root.sourceCompilerForInline.compilationContextDescriptor.builtIns.nullableAnyType + val nullableAnyType = inliningContext.state.module.builtIns.nullableAnyType val expectedParameters = info.invokeMethod.argumentTypes val expectedKotlinParameters = info.invokeMethodParameters val argumentCount = Type.getArgumentTypes(desc).size.let { @@ -825,7 +823,7 @@ class MethodInliner( getFunctionalArgumentIfExists((insnNode as VarInsnNode).`var`) insnNode is FieldInsnNode && insnNode.name.startsWith(CAPTURED_FIELD_FOLD_PREFIX) -> findCapturedField(insnNode, nodeRemapper).functionalArgument - insnNode is FieldInsnNode && insnNode.isSuspendLambdaCapturedByOuterObjectOrLambda(inliningContext) -> + insnNode is FieldInsnNode && inliningContext.root.sourceCompilerForInline.isSuspendLambdaCapturedByOuterObjectOrLambda(insnNode.name) -> NonInlineableArgumentForInlineableParameterCalledInSuspend else -> null diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt index 5be16b24416..c68f51c6570 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt @@ -7,7 +7,9 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.psi.PsiElement import org.jetbrains.kotlin.backend.common.CodegenUtil +import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.context.* import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView import org.jetbrains.kotlin.codegen.state.GenerationState @@ -21,11 +23,13 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.isInlineClass import org.jetbrains.kotlin.resolve.jvm.annotations.isCallableMemberCompiledToJvmDefault import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.expressions.LabelResolver import org.jetbrains.kotlin.utils.addIfNotNull @@ -76,8 +80,8 @@ class PsiSourceCompilerForInline( parentCodegen.className, signature.asmMethod.name, signature.asmMethod.descriptor, - compilationContextFunctionDescriptor.isInlineOrInsideInline(), - compilationContextFunctionDescriptor.isSuspend, + context.functionDescriptor.isInlineOrInsideInline(), + context.functionDescriptor.isSuspend, CodegenUtil.getLineNumberForElement(callElement, false) ?: 0 ) } @@ -314,11 +318,33 @@ class PsiSourceCompilerForInline( override val isFinallyMarkerRequired: Boolean get() = isFinallyMarkerRequired(codegen.getContext()) - override val compilationContextDescriptor - get() = codegen.getContext().contextDescriptor - - override val compilationContextFunctionDescriptor - get() = codegen.getContext().functionDescriptor + override fun isSuspendLambdaCapturedByOuterObjectOrLambda(name: String): Boolean { + // We cannot find the lambda in captured parameters: it came from object outside of the our reach: + // this can happen when the lambda capture by non-transformed closure: + // inline fun inlineMe(crossinline c: suspend() -> Unit) = suspend { c() } + // inline fun inlineMe2(crossinline c: suspend() -> Unit) = suspend { inlineMe { c() }() } + // Suppose, we inline inlineMe into inlineMe2: the only knowledge we have about inlineMe$1 is captured receiver (this$0) + // Thus, transformed lambda from inlineMe, inlineMe3$$inlined$inlineMe2$1 contains the following bytecode + // ALOAD 0 + // GETFIELD inlineMe2$1$invokeSuspend$$inlined$inlineMe$1.this$0 : LScratchKt$inlineMe2$1; + // GETFIELD inlineMe2$1.$c : Lkotlin/jvm/functions/Function1; + // Since inlineMe2's lambda is outside of reach of the inliner, find crossinline parameter from compilation context: + var container: DeclarationDescriptor = codegen.getContext().functionDescriptor + while (container !is ClassDescriptor) { + container = container.containingDeclaration ?: return false + } + var classDescriptor: ClassDescriptor? = container + while (classDescriptor != null) { + val closure = state.bindingContext[CodegenBinding.CLOSURE, classDescriptor] ?: return false + for ((param, value) in closure.captureVariables) { + if (param is ValueParameterDescriptor && value.fieldName == name) { + return param.type.isSuspendFunctionTypeOrSubtype + } + } + classDescriptor = closure.capturedOuterClassDescriptor + } + return false + } override fun getContextLabels(): Map { val context = codegen.getContext() 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 d8355c73a8e..9509a4c3455 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt @@ -11,14 +11,13 @@ import org.jetbrains.kotlin.codegen.BaseExpressionCodegen import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.incremental.components.LocationInfo import org.jetbrains.kotlin.incremental.components.Position import org.jetbrains.kotlin.incremental.components.ScopeKind import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.Method @@ -54,9 +53,7 @@ interface SourceCompilerForInline { val isFinallyMarkerRequired: Boolean - val compilationContextDescriptor: DeclarationDescriptor - - val compilationContextFunctionDescriptor: FunctionDescriptor + fun isSuspendLambdaCapturedByOuterObjectOrLambda(name: String): Boolean fun getContextLabels(): Map 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 896c9b21248..f25602c2312 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,18 +6,13 @@ package org.jetbrains.kotlin.codegen.inline.coroutines import com.intellij.util.ArrayUtil -import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype import org.jetbrains.kotlin.codegen.ClassBuilder -import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.coroutines.* import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.isReleaseCoroutines -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.org.objectweb.asm.MethodVisitor @@ -238,35 +233,6 @@ fun surroundInvokesWithSuspendMarkersIfNeeded(node: MethodNode) { } } -// We cannot find the lambda in captured parameters: it came from object outside of the our reach: -// this can happen when the lambda capture by non-transformed closure: -// inline fun inlineMe(crossinline c: suspend() -> Unit) = suspend { c() } -// inline fun inlineMe2(crossinline c: suspend() -> Unit) = suspend { inlineMe { c() }() } -// Suppose, we inline inlineMe into inlineMe2: the only knowledge we have about inlineMe$1 is captured receiver (this$0) -// Thus, transformed lambda from inlineMe, inlineMe3$$inlined$inlineMe2$1 contains the following bytecode -// ALOAD 0 -// GETFIELD inlineMe2$1$invokeSuspend$$inlined$inlineMe$1.this$0 : LScratchKt$inlineMe2$1; -// GETFIELD inlineMe2$1.$c : Lkotlin/jvm/functions/Function1; -// Since inlineMe2's lambda is outside of reach of the inliner, find crossinline parameter from compilation context: -fun FieldInsnNode.isSuspendLambdaCapturedByOuterObjectOrLambda(inliningContext: InliningContext): Boolean { - var container: DeclarationDescriptor = inliningContext.root.sourceCompilerForInline.compilationContextFunctionDescriptor - while (container !is ClassDescriptor) { - container = container.containingDeclaration ?: return false - } - val bindingContext = inliningContext.state.bindingContext - var classDescriptor: ClassDescriptor? = container - while (classDescriptor != null) { - val closure = bindingContext[CodegenBinding.CLOSURE, classDescriptor] ?: return false - for ((param, value) in closure.captureVariables) { - if (param is ValueParameterDescriptor && value.fieldName == name) { - return param.type.isSuspendFunctionTypeOrSubtype - } - } - classDescriptor = closure.capturedOuterClassDescriptor - } - return false -} - // Interpreter, that keeps track of captured functional arguments private class PossibleLambdaLoad(val insn: AbstractInsnNode) : BasicValue(AsmTypes.OBJECT_TYPE) 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 d6fe558503e..58c5e158020 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 @@ -14,8 +14,6 @@ import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledReturnType import org.jetbrains.kotlin.codegen.BaseExpressionCodegen import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.incremental.components.LocationInfo import org.jetbrains.kotlin.incremental.components.Position @@ -32,6 +30,7 @@ import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.doNotAnalyze import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -122,11 +121,8 @@ class IrSourceCompilerForInline( override val isFinallyMarkerRequired: Boolean get() = codegen.isFinallyMarkerRequired - override val compilationContextDescriptor: DeclarationDescriptor - get() = compilationContextFunctionDescriptor - - override val compilationContextFunctionDescriptor: FunctionDescriptor - get() = generateSequence(codegen) { it.inlinedInto }.last().irFunction.toIrBasedDescriptor() + override fun isSuspendLambdaCapturedByOuterObjectOrLambda(name: String): Boolean = + false // IR does not capture variables through outer this override fun getContextLabels(): Map { val result = mutableMapOf(codegen.irFunction.name.asString() to null)