diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index 38fc7d23047..6f80e356101 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -131,20 +131,21 @@ abstract class DefaultLambda( }?.toList() ?: emptyList() isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty() - val invokeName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString() - val invokeDescriptor = mapAsmDescriptor(sourceCompiler, isPropertyReference) + val invokeNameFallback = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString() + val invokeMethod = mapAsmMethod(sourceCompiler, isPropertyReference) // TODO: `signatureAmbiguity = true` ignores the argument types from `invokeDescriptor` and only looks at the count. // This effectively masks incorrect results from `mapAsmDescriptor`, which hopefully won't manifest in another way. - node = getMethodNode(classBytes, invokeName, invokeDescriptor, lambdaClassType, signatureAmbiguity = true) - ?: error("Can't find method '$invokeName$invokeDescriptor' in '${lambdaClassType.internalName}'") - invokeMethod = Method(node.node.name, node.node.desc) + node = getMethodNode(classBytes, invokeMethod.name, invokeMethod.descriptor, lambdaClassType, signatureAmbiguity = true) + ?: getMethodNode(classBytes, invokeNameFallback, invokeMethod.descriptor, lambdaClassType, signatureAmbiguity = true) + ?: error("Can't find method '$invokeMethod' in '${lambdaClassType.internalName}'") + this.invokeMethod = Method(node.node.name, node.node.desc) if (needReification) { //nested classes could also require reification reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(node.node)) } } - protected abstract fun mapAsmDescriptor(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): String + protected abstract fun mapAsmMethod(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): Method private companion object { val PROPERTY_REFERENCE_SUPER_CLASSES = diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt index 38d4114e5c9..81907aedcb0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -351,7 +351,7 @@ class PsiDefaultLambda( override val invokeMethodReturnType: KotlinType? get() = invokeMethodDescriptor.returnType - override fun mapAsmDescriptor(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): String { + override fun mapAsmMethod(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): Method { invokeMethodDescriptor = parameterDescriptor.type.memberScope .getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND) .single().let { @@ -359,6 +359,6 @@ class PsiDefaultLambda( // have a non-erased `invoke` with an erased synthetic bridge, and we want to inline the former. if (isPropertyReference) it.original else it } - return sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor + return sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index 5faa21bea18..0fe25404627 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -6,7 +6,9 @@ package org.jetbrains.kotlin.backend.jvm.codegen import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter +import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi import org.jetbrains.kotlin.codegen.IrExpressionLambda import org.jetbrains.kotlin.codegen.JvmKotlinType import org.jetbrains.kotlin.codegen.StackValue @@ -24,6 +26,7 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.tree.MethodNode @@ -245,7 +248,7 @@ class IrDefaultLambda( override val invokeMethodReturnType: KotlinType get() = typeArguments.last().toIrBasedKotlinType() - override fun mapAsmDescriptor(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): String { + override fun mapAsmMethod(sourceCompiler: SourceCompilerForInline, isPropertyReference: Boolean): Method { val context = (sourceCompiler as IrSourceCompilerForInline).codegen.context typeArguments = (irValueParameter.type as IrSimpleType).arguments.let { // Property references only have an erased `get` method, while function references and lambdas @@ -256,9 +259,15 @@ class IrDefaultLambda( it.map { argument -> (argument as IrTypeProjection).type } } } + val base = if (isPropertyReference) OperatorNameConventions.GET.asString() else OperatorNameConventions.INVOKE.asString() + val name = InlineClassAbi.hashSuffix( + context.state.useOldManglingSchemeForFunctionsWithInlineClassesInSignatures, + typeArguments.dropLast(1), + typeArguments.last().takeIf { it.isInlineClassType() } + )?.let { "$base-$it" } ?: base // TODO: while technically only the number of arguments here matters right now (see DefaultLambdaInfo.generateLambdaBody), // it would be better to map to a non-erased signature if not a property reference. - return Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, *Array(typeArguments.size - 1) { AsmTypes.OBJECT_TYPE }) + return Method(name, AsmTypes.OBJECT_TYPE, Array(typeArguments.size - 1) { AsmTypes.OBJECT_TYPE }) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt index 62d2db7dcd4..76d1b6ceca7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt @@ -63,7 +63,15 @@ object InlineClassAbi { return Name.identifier("constructor-impl") } - val suffix = hashSuffix(irFunction, mangleReturnTypes, useOldMangleRules) ?: return irFunction.name + val suffix = hashSuffix( + useOldMangleRules, + irFunction.fullValueParameterList.map { it.type }, + irFunction.returnType.takeIf { mangleReturnTypes && irFunction.hasMangledReturnType }, + irFunction.isSuspend + ) + if (suffix == null && ((irFunction.parent as? IrClass)?.isInline != true || irFunction.origin == IrDeclarationOrigin.IR_BUILTINS_STUB)) { + return irFunction.name + } val base = when { irFunction.isGetter -> @@ -76,47 +84,28 @@ object InlineClassAbi { irFunction.name.asString() } - return Name.identifier("$base-$suffix") + return Name.identifier("$base-${suffix ?: "impl"}") } - private fun hashSuffix( - irFunction: IrFunction, - mangleReturnTypes: Boolean, + fun hashSuffix( useOldMangleRules: Boolean, - alwaysMangleReturnType: Boolean = false - ): String? { - val signatureForMangling = collectFunctionSignatureForManglingSuffix( - useOldManglingRules = useOldMangleRules, - requiresFunctionNameManglingForParameterTypes = irFunction.fullValueParameterList.any { it.type.requiresMangling }, - fqNamesForMangling = irFunction.fullValueParameterList.map { - it.type.asInfoForMangling() - } + listOfNotNull( - // The JVM backend computes mangled names after creating suspend function views, but before default argument - // stub insertion. It would be nice if this part of the continuation lowering happened earlier in the pipeline. - // TODO: Move suspend function view creation before JvmInlineClassLowering. - if (irFunction.isSuspend) - InfoForMangling(FqNameUnsafe("kotlin.coroutines.Continuation"), isInline = false, isNullable = false) - else null - ), - returnTypeInfo = if (alwaysMangleReturnType || (mangleReturnTypes && irFunction.hasMangledReturnType)) { - irFunction.returnType.asInfoForMangling() - } else null - ) - - return when { - signatureForMangling != null -> md5base64(signatureForMangling) - (irFunction.parent as? IrClass)?.isInline == true && irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB -> "impl" - else -> null - } - } - - fun hashReturnSuffix(irFunction: IrFunction): String = - hashSuffix( - irFunction, - mangleReturnTypes = true, - useOldMangleRules = false, - alwaysMangleReturnType = true - )!! + valueParameters: List, + returnType: IrType?, + addContinuation: Boolean = false + ): String? = + collectFunctionSignatureForManglingSuffix( + useOldMangleRules, + valueParameters.any { it.requiresMangling }, + // The JVM backend computes mangled names after creating suspend function views, but before default argument + // stub insertion. It would be nice if this part of the continuation lowering happened earlier in the pipeline. + // TODO: Move suspend function view creation before JvmInlineClassLowering. + if (addContinuation) + valueParameters.map { it.asInfoForMangling() } + + InfoForMangling(FqNameUnsafe("kotlin.coroutines.Continuation"), isInline = false, isNullable = false) + else + valueParameters.map { it.asInfoForMangling() }, + returnType?.asInfoForMangling() + )?.let(::md5base64) private fun IrType.asInfoForMangling(): InfoForMangling = InfoForMangling( diff --git a/compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/callableReferences/withInlineClassParameter.kt b/compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/callableReferences/withInlineClassParameter.kt index 10c645987b3..eab5f2fa802 100644 --- a/compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/callableReferences/withInlineClassParameter.kt +++ b/compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/callableReferences/withInlineClassParameter.kt @@ -1,7 +1,3 @@ -// KT-46601 -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR, JVM_MULTI_MODULE_OLD_AGAINST_IR // SKIP_INLINE_CHECK_IN: inlineFun-1BDWgbU$default // FILE: 1.kt package test