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 75fd6b0263c..99bf18b4b74 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 @@ -133,7 +133,7 @@ class JvmBackendContext( val staticDefaultStubs = mutableMapOf() - val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory) + val inlineClassReplacements = MemoizedInlineClassReplacements(state.functionsWithInlineClassReturnTypesMangled, irFactory, this) internal fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol = symbolTable.lazyWrapper.referenceClass(descriptor) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt index fcd940f528d..2f1c4bbf2d9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.Method class IrFrameMap : FrameMapBase() { private val typeMap = mutableMapOf() @@ -376,3 +377,13 @@ val IrMemberAccessExpression<*>.psiElement: PsiElement? fun IrSimpleType.isRawType(): Boolean = hasAnnotation(JvmGeneratorExtensions.RAW_TYPE_ANNOTATION_FQ_NAME) + +@OptIn(ObsoleteDescriptorBasedAPI::class) +internal fun classFileContainsMethod(function: IrFunction, context: JvmBackendContext, name: String): Boolean? { + val originalDescriptor = context.methodSignatureMapper.mapSignatureWithGeneric(function).asmMethod.descriptor + val descriptor = if (function.isSuspend) + listOf(*Type.getArgumentTypes(originalDescriptor), Type.getObjectType("kotlin/coroutines/Continuation")) + .joinToString(prefix = "(", postfix = ")", separator = "") + AsmTypes.OBJECT_TYPE + else originalDescriptor + return classFileContainsMethod(function.descriptor, context.state, Method(name, descriptor)) +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt index 7587f6d4095..6311e18e4e6 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FunctionReferenceLowering.kt @@ -369,7 +369,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext) name = if (samSuperType == null && callee.returnType.erasedUpperBound.isInline && context.state.functionsWithInlineClassReturnTypesMangled) { // For functions with inline class return type we need to mangle the invoke method. // Otherwise, bridge lowering may fail to generate bridges for inline class types erasing to Any. - val suffix = InlineClassAbi.hashSuffix(callee, true) + val suffix = InlineClassAbi.hashSuffix(callee, mangleReturnTypes = true, useOldMangleRules = false) Name.identifier("${superMethod.owner.name.asString()}-${suffix}") } else superMethod.owner.name returnType = callee.returnType 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 a4f811e8633..c5ee48e5b78 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 @@ -62,7 +62,7 @@ object InlineClassAbi { * Returns a mangled name for a function taking inline class arguments * to avoid clashes between overloaded methods. */ - fun mangledNameFor(irFunction: IrFunction, mangleReturnTypes: Boolean): Name { + fun mangledNameFor(irFunction: IrFunction, mangleReturnTypes: Boolean, useOldMangleRules: Boolean): Name { if (irFunction is IrConstructor) { // Note that we might drop this convention and use standard mangling for constructors too, see KT-37186. assert(irFunction.constructedClass.isInline) { @@ -71,14 +71,28 @@ object InlineClassAbi { return Name.identifier("constructor-impl") } - val suffix = when { - irFunction.fullValueParameterList.any { it.type.requiresMangling } || (mangleReturnTypes && irFunction.hasMangledReturnType) -> - hashSuffix(irFunction, mangleReturnTypes) - (irFunction.parent as? IrClass)?.isInline == true && - irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB -> - "impl" - else -> - return irFunction.name + val suffix = if (useOldMangleRules) { + when { + irFunction.fullValueParameterList.any { it.type.requiresMangling } -> + hashSuffix(irFunction, false, useOldMangleRules) + mangleReturnTypes && irFunction.hasMangledReturnType -> + returnHashSuffix(irFunction) + (irFunction.parent as? IrClass)?.isInline == true && + irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB -> + "impl" + else -> + return irFunction.name + } + } else { + when { + irFunction.fullValueParameterList.any { it.type.requiresMangling } || (mangleReturnTypes && irFunction.hasMangledReturnType) -> + hashSuffix(irFunction, mangleReturnTypes, useOldMangleRules) + (irFunction.parent as? IrClass)?.isInline == true && + irFunction.origin != IrDeclarationOrigin.IR_BUILTINS_STUB -> + "impl" + else -> + return irFunction.name + } } val base = when { @@ -98,26 +112,40 @@ object InlineClassAbi { private val IrFunction.propertyName: Name get() = (this as IrSimpleFunction).correspondingPropertySymbol!!.owner.name - fun hashSuffix(irFunction: IrFunction, mangleReturnTypes: Boolean): String { + fun hashSuffix(irFunction: IrFunction, mangleReturnTypes: Boolean, useOldMangleRules: Boolean): String { val signatureElementsForMangling = - irFunction.fullValueParameterList.mapTo(mutableListOf()) { it.type.eraseToString() } + irFunction.fullValueParameterList.mapTo(mutableListOf()) { it.type.eraseToString(useOldMangleRules) } if (irFunction.isSuspend) { // 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. - signatureElementsForMangling += "x" + signatureElementsForMangling += if (useOldMangleRules) "Lkotlin.coroutines.Continuation;" else "x" } val signatureString = signatureElementsForMangling.joinToString() + - if (mangleReturnTypes && irFunction.hasMangledReturnType) ":${irFunction.returnType.eraseToString()}" else "" + if (mangleReturnTypes && irFunction.hasMangledReturnType && !useOldMangleRules) + ":${irFunction.returnType.eraseToString(useOldMangleRules)}" else "" return md5base64(signatureString) } - private fun IrType.eraseToString() = if (getClass()?.isInline == true) buildString { - append('L') - append(erasedUpperBound.fqNameWhenAvailable!!) - if (isNullable()) append('?') - append(';') - } else "x" + private fun returnHashSuffix(irFunction: IrFunction) = + md5base64(":${irFunction.returnType.eraseToString(false)}") + + private fun IrType.eraseToString(useOldMangleRules: Boolean) = + if (useOldMangleRules) { + buildString { + append('L') + append(erasedUpperBound.fqNameWhenAvailable!!) + if (isNullable()) append('?') + append(';') + } + } else { + if (getClass()?.isInline == true) buildString { + append('L') + append(erasedUpperBound.fqNameWhenAvailable!!) + if (isNullable()) append('?') + append(';') + } else "x" + } } internal val IrType.requiresMangling: Boolean diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt index 1625006c782..2336e5dfa3e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt @@ -9,7 +9,9 @@ import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.copyTypeParameters import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.backend.jvm.codegen.classFileContainsMethod import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi.mangledNameFor import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper @@ -33,7 +35,11 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs /** * Keeps track of replacement functions and inline class box/unbox functions. */ -class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean, private val irFactory: IrFactory) { +class MemoizedInlineClassReplacements( + private val mangleReturnTypes: Boolean, + private val irFactory: IrFactory, + private val context: JvmBackendContext +) { private val storageManager = LockBasedStorageManager("inline-class-replacements") private val propertyMap = mutableMapOf() @@ -215,7 +221,10 @@ class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean, pr if (noFakeOverride) { isFakeOverride = false } - name = mangledNameFor(function, mangleReturnTypes) + name = mangledNameFor(function, mangleReturnTypes, false) + if (name.asString().contains("-") && classFileContainsMethod(function, context, name.asString()) == false) { + name = mangledNameFor(function, mangleReturnTypes, true) + } returnType = function.returnType }.apply { parent = function.parent