From 6142d75bb43de016958239688827a977c9cf90b9 Mon Sep 17 00:00:00 2001 From: Sergej Jaskiewicz Date: Thu, 22 Jun 2023 15:55:57 +0200 Subject: [PATCH] [klib] Serialized mangled names of declarations along with signatures ^KT-59486 Fixed --- .../signaturer/FirBasedSignatureComposer.kt | 45 +++++++++++-------- .../backend/js/ic/IdSignatureSerialization.kt | 23 +++------- .../irToJs/IrModuleToJsTransformer.kt | 10 ++++- .../kotlin/ir/util/IdSignatureRenderer.kt | 34 ++++++++++++++ .../common/serialization/IrFileSerializer.kt | 7 +++ .../signature/IdSignatureBuilder.kt | 4 +- .../signature/IdSignatureDescriptor.kt | 24 +++++++--- 7 files changed, 103 insertions(+), 44 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirBasedSignatureComposer.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirBasedSignatureComposer.kt index badccd50810..979504d5d0e 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirBasedSignatureComposer.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirBasedSignatureComposer.kt @@ -27,6 +27,10 @@ class FirBasedSignatureComposer(val mangler: FirMangler) { private val signatureCache = mutableMapOf() + private fun computeSignatureHashAndDescriptionFor(declaration: FirDeclaration): Pair = mangler.run { + declaration.signatureString(compatibleMode = false).let { it.hashMangle to it } + } + fun composeSignature(declaration: FirClassLikeDeclaration): IdSignature? { return composeSignatureImpl(declaration, containingClass = null, forceExpect = false) } @@ -72,24 +76,19 @@ class FirBasedSignatureComposer(val mangler: FirMangler) { } else -> return null } - val id = with(mangler) { - if (isSetter) { - property.setterOrDefault().signatureMangle(compatibleMode = false) - } else { - property.getterOrDefault().signatureMangle(compatibleMode = false) - } - } - val accessorFqName = if (isSetter) { - propSig.declarationFqName + "." + val accessor = if (isSetter) { + property.setterOrDefault() } else { - propSig.declarationFqName + "." + property.getterOrDefault() } + val (id, description) = computeSignatureHashAndDescriptionFor(accessor) + val accessorFqName = "${propSig.declarationFqName}.${accessor.irName}" val commonSig = IdSignature.CommonSignature( packageFqName = propSig.packageFqName, declarationFqName = accessorFqName, id = id, mask = propSig.mask, - description = null, // TODO(KT-59486): Save mangled name here + description = description, ) val accessorSig = IdSignature.AccessorSignature(propSig, commonSig) return if (fileSig != null) { @@ -140,7 +139,7 @@ class FirBasedSignatureComposer(val mangler: FirMangler) { declarationFqName = classId.relativeClassName.asString(), id = builder.hashId, mask = builder.mask, - description = null, // TODO(KT-59486): Save mangled name here + description = builder.description, ) } is FirTypeAlias -> { @@ -150,7 +149,7 @@ class FirBasedSignatureComposer(val mangler: FirMangler) { declarationFqName = classId.relativeClassName.asString(), id = builder.hashId, mask = builder.mask, - description = null, // TODO(KT-59486): Save mangled name here + description = builder.description, ) } is FirCallableDeclaration -> { @@ -163,7 +162,7 @@ class FirBasedSignatureComposer(val mangler: FirMangler) { declarationFqName = classId?.relativeClassName?.child(callableName)?.asString() ?: callableName.asString(), id = builder.hashId, mask = builder.mask, - description = null, // TODO(KT-59486): Save mangled name here + description = builder.description, ) } is FirScript -> { @@ -172,7 +171,7 @@ class FirBasedSignatureComposer(val mangler: FirMangler) { declarationFqName = declaration.name.asString(), id = builder.hashId, mask = builder.mask, - description = null, // TODO(KT-59486): Save mangled name here + description = builder.description, ) } else -> error("Unsupported FIR declaration in signature composer: ${declaration.render()}") @@ -181,8 +180,16 @@ class FirBasedSignatureComposer(val mangler: FirMangler) { private inner class SignatureBuilder(private val forceExpect: Boolean) : FirVisitor() { var hashId: Long? = null + var description: String? = null var mask = 0L + private fun setHashAndDescriptionFor(declaration: FirDeclaration) { + computeSignatureHashAndDescriptionFor(declaration).let { + hashId = it.first + description = it.second + } + } + private fun setExpected(f: Boolean) { mask = mask or IdSignature.Flags.IS_EXPECT.encode(f || forceExpect) } @@ -204,22 +211,22 @@ class FirBasedSignatureComposer(val mangler: FirMangler) { } override fun visitConstructor(constructor: FirConstructor, data: Any?) { - hashId = mangler.run { constructor.signatureMangle(compatibleMode = false) } + setHashAndDescriptionFor(constructor) setExpected(constructor.isExpect) } override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Any?) { - hashId = mangler.run { simpleFunction.signatureMangle(compatibleMode = false) } + setHashAndDescriptionFor(simpleFunction) setExpected(simpleFunction.isExpect) } override fun visitProperty(property: FirProperty, data: Any?) { - hashId = mangler.run { property.signatureMangle(compatibleMode = false) } + setHashAndDescriptionFor(property) setExpected(property.isExpect) } override fun visitField(field: FirField, data: Any?) { - hashId = mangler.run { field.signatureMangle(compatibleMode = false) } + setHashAndDescriptionFor(field) setExpected(field.isExpect) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IdSignatureSerialization.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IdSignatureSerialization.kt index 18cf51da75f..a87066b890e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IdSignatureSerialization.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IdSignatureSerialization.kt @@ -46,14 +46,9 @@ internal class IdSignatureSerialization(private val library: KotlinLibraryHeader out.writeInt32NoTag(IdSignatureProtoType.COMMON_SIGNATURE.id) out.writeStringNoTag(signature.packageFqName) out.writeStringNoTag(signature.declarationFqName) - val id = signature.id - if (id != null) { - out.writeBoolNoTag(true) - out.writeFixed64NoTag(id) - } else { - out.writeBoolNoTag(false) - } + out.ifNotNull(signature.id, out::writeFixed64NoTag) out.writeInt64NoTag(signature.mask) + out.ifNotNull(signature.description, out::writeStringNoTag) } is IdSignature.CompositeSignature -> { out.writeInt32NoTag(IdSignatureProtoType.COMPOSITE_SIGNATURE.id) @@ -82,18 +77,15 @@ internal class IdSignatureSerialization(private val library: KotlinLibraryHeader IdSignatureProtoType.COMMON_SIGNATURE.id -> { val packageFqName = input.readString() val declarationFqName = input.readString() - val id = if (input.readBool()) { - input.readFixed64() - } else { - null - } + val id = input.ifTrue(input::readFixed64) val mask = input.readInt64() + val description = input.ifTrue(input::readString) return IdSignature.CommonSignature( packageFqName = packageFqName, declarationFqName = declarationFqName, id = id, mask = mask, - description = null, // TODO(KT-59486): Deserialize mangled name and save it here + description = description, ) } IdSignatureProtoType.COMPOSITE_SIGNATURE.id -> { @@ -123,10 +115,9 @@ internal class IdSignatureSerialization(private val library: KotlinLibraryHeader IdSignatureProtoType.COMMON_SIGNATURE.id -> { input.readString() input.readString() - if (input.readBool()) { - input.readFixed64() - } + input.ifTrue(input::readFixed64) input.readInt64() + input.ifTrue(input::readString) } IdSignatureProtoType.COMPOSITE_SIGNATURE.id -> { skipIdSignature(input) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt index 5035a80637d..257d02a8bcc 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.util.IdSignatureRenderer import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor @@ -418,7 +419,14 @@ class IrModuleToJsTransformer( } private fun Set.computeTag(declaration: IrDeclaration): String? { - val tag = (backendContext.irFactory as IdSignatureRetriever).declarationSignature(declaration)?.render() + // Use LEGACY here because the declaration may come from an old klib, in which its `IdSignature.CommonSignature` + // doesn't have `description`, but only `id`. Hence, we always render the signature with `id` instead of `description`, + // because otherwise there may be a mismatch when we're computing the tag first for the IrDeclaration deserialized from klib, + // and then for the same declaration but constructed from a descriptor. + // + // The former won't have `description` in its `IdSignature`, the latter will have it, + // which will result in different renders unless we use the LEGACY renderer. + val tag = (backendContext.irFactory as IdSignatureRetriever).declarationSignature(declaration)?.render(IdSignatureRenderer.LEGACY) if (tag == null && !contains(declaration)) { error("signature for ${declaration.render()} not found") diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignatureRenderer.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignatureRenderer.kt index 4a3978b27aa..1a5dec2c55e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignatureRenderer.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignatureRenderer.kt @@ -69,7 +69,41 @@ class IdSignatureRenderer private constructor(private val showDescriptionForPubl } companion object { + + /** + * The renderer which ignores [IdSignature.CommonSignature.id] and renders its [IdSignature.CommonSignature.description] instead. + * + * This results in more human-readable representations of signatures. + * + * If [IdSignature.CommonSignature.description] is `null`, falls back to rendering [IdSignature.CommonSignature.id]. + * + * For example, for the following function: + * + * ```kotlin + * package com.example + * + * fun box(): String {} + * ``` + * + * its signature rendered with the [DEFAULT] renderer will look like `com.example/box|box(){}[0]` + * whereas when using the [LEGACY] renderer, it will look like `com.example/box|2173511048851971368[0]`. + */ val DEFAULT = IdSignatureRenderer(showDescriptionForPublicSignatures = true) + + /** + * The renderer which ignores [IdSignature.CommonSignature.description] and renders its [IdSignature.CommonSignature.id] instead. + * + * For example, for the following function: + * + * ```kotlin + * package com.example + * + * fun box(): String {} + * ``` + * + * its signature rendered with the [LEGACY] renderer will look like `com.example/box|2173511048851971368[0]` + * whereas when using the [DEFAULT] renderer, it will look like `com.example/box|box(){}[0]`. + */ val LEGACY = IdSignatureRenderer(showDescriptionForPublicSignatures = false) } } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt index c985b695fe8..94a087f7ad2 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt @@ -215,6 +215,10 @@ open class IrFileSerializer( proto.flags = signature.mask } + if (addDebugInfo) { + signature.description?.let { proto.debugInfo = serializeDebugInfo(it) } + } + return proto.build() } @@ -228,6 +232,9 @@ open class IrFileSerializer( if (mask != 0L) { proto.flags = mask } + if (addDebugInfo) { + description?.let { proto.debugInfo = serializeDebugInfo(it) } + } } return proto.build() diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureBuilder.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureBuilder.kt index d241dc6fe12..a66f9a97bc5 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureBuilder.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureBuilder.kt @@ -74,7 +74,7 @@ abstract class IdSignatureBuilder { declarationFqName = classFqName, id = hashId, mask = mask, - description = null, // TODO(KT-59486): Save mangled name here + description = description, ) } else -> { @@ -83,7 +83,7 @@ abstract class IdSignatureBuilder { declarationFqName = classFqName, id = hashIdAcc, mask = mask, - description = null, // TODO(KT-59486): Save mangled name here + description = description, ) hashIdAcc = null classFqnSegments.run { removeAt(lastIndex) } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureDescriptor.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureDescriptor.kt index 16ccc929e21..d5adec9fd53 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureDescriptor.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureDescriptor.kt @@ -23,6 +23,19 @@ open class IdSignatureDescriptor(override val mangler: KotlinMangler.DescriptorM IdSignatureBuilder(), DeclarationDescriptorVisitor { + private fun setHashIdFor(declaration: DeclarationDescriptor, isPropertyAccessor: Boolean) { + mangler.run { + val mangledName = declaration.signatureString(compatibleMode = false) + val id = mangledName.hashMangle + if (isPropertyAccessor) { + hashIdAcc = id + } else { + hashId = id + } + description = mangledName + } + } + override fun accept(d: DeclarationDescriptor) { d.accept(this, null) } @@ -71,7 +84,7 @@ open class IdSignatureDescriptor(override val mangler: KotlinMangler.DescriptorM override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Nothing?) { collectParents(descriptor) - hashId = mangler.run { descriptor.signatureMangle(compatibleMode = false) } + setHashIdFor(descriptor, isPropertyAccessor = false) isTopLevelPrivate = isTopLevelPrivate or descriptor.isTopLevelPrivate setDescription(descriptor) setExpected(descriptor.isExpect) @@ -115,7 +128,7 @@ open class IdSignatureDescriptor(override val mangler: KotlinMangler.DescriptorM override fun visitConstructorDescriptor(constructorDescriptor: ConstructorDescriptor, data: Nothing?) { collectParents(constructorDescriptor) - hashId = mangler.run { constructorDescriptor.signatureMangle(compatibleMode = false) } + setHashIdFor(constructorDescriptor, isPropertyAccessor = false) platformSpecificConstructor(constructorDescriptor) } @@ -131,8 +144,7 @@ open class IdSignatureDescriptor(override val mangler: KotlinMangler.DescriptorM collectParents(actualDeclaration) isTopLevelPrivate = isTopLevelPrivate or actualDeclaration.isTopLevelPrivate - - hashId = mangler.run { actualDeclaration.signatureMangle(compatibleMode = false) } + setHashIdFor(actualDeclaration, isPropertyAccessor = false) setExpected(actualDeclaration.isExpect) platformSpecificProperty(actualDeclaration) if (type == SpecialDeclarationType.BACKING_FIELD) { @@ -149,7 +161,7 @@ open class IdSignatureDescriptor(override val mangler: KotlinMangler.DescriptorM override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor, data: Nothing?) { descriptor.correspondingProperty.accept(this, null) - hashIdAcc = mangler.run { descriptor.signatureMangle(compatibleMode = false) } + setHashIdFor(descriptor, isPropertyAccessor = true) classFqnSegments.add(descriptor.name.asString()) setExpected(descriptor.isExpect) platformSpecificGetter(descriptor) @@ -157,7 +169,7 @@ open class IdSignatureDescriptor(override val mangler: KotlinMangler.DescriptorM override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor, data: Nothing?) { descriptor.correspondingProperty.accept(this, null) - hashIdAcc = mangler.run { descriptor.signatureMangle(compatibleMode = false) } + setHashIdFor(descriptor, isPropertyAccessor = true) classFqnSegments.add(descriptor.name.asString()) setExpected(descriptor.isExpect) platformSpecificSetter(descriptor)