[klib] Serialized mangled names of declarations along with signatures

^KT-59486 Fixed
This commit is contained in:
Sergej Jaskiewicz
2023-06-22 15:55:57 +02:00
committed by Space Team
parent 10aa5fc7ef
commit 6142d75bb4
7 changed files with 103 additions and 44 deletions
@@ -27,6 +27,10 @@ class FirBasedSignatureComposer(val mangler: FirMangler) {
private val signatureCache = mutableMapOf<FirDeclarationWithParentId, IdSignature.CommonSignature>()
private fun computeSignatureHashAndDescriptionFor(declaration: FirDeclaration): Pair<Long, String> = 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 + ".<set-${property.name.asString()}>"
val accessor = if (isSetter) {
property.setterOrDefault()
} else {
propSig.declarationFqName + ".<get-${property.name.asString()}>"
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<Unit, Any?>() {
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)
}
@@ -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)
@@ -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<IrDeclaration>.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")
@@ -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)
}
}
@@ -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()
@@ -74,7 +74,7 @@ abstract class IdSignatureBuilder<D> {
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<D> {
declarationFqName = classFqName,
id = hashIdAcc,
mask = mask,
description = null, // TODO(KT-59486): Save mangled name here
description = description,
)
hashIdAcc = null
classFqnSegments.run { removeAt(lastIndex) }
@@ -23,6 +23,19 @@ open class IdSignatureDescriptor(override val mangler: KotlinMangler.DescriptorM
IdSignatureBuilder<DeclarationDescriptor>(),
DeclarationDescriptorVisitor<Unit, Nothing?> {
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)