Unify JvmSignatureSerializer

This commit is contained in:
Ivan Kochurkin
2023-06-30 14:38:33 +03:00
committed by Space Team
parent 4d24a8b40c
commit 20c53fc15d
3 changed files with 164 additions and 202 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmFlags
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.metadata.serialization.StringTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -39,7 +40,6 @@ import org.jetbrains.kotlin.serialization.SerializerExtension
import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.Method
class JvmSerializerExtension @JvmOverloads constructor(
private val bindings: JvmSerializationBindings,
@@ -60,6 +60,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
private val jvmDefaultMode = state.jvmDefaultMode
private val approximator = state.typeApproximator
private val useOldManglingScheme = state.useOldManglingSchemeForFunctionsWithInlineClassesInSignatures
private val signatureSerializer = JvmSignatureSerializerImpl(stringTable)
override fun shouldUseTypeTable(): Boolean = useTypeTable
@@ -163,7 +164,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
) {
val method = getBinding(METHOD_FOR_FUNCTION, descriptor)
if (method != null) {
val signature = SignatureSerializer().methodSignature(descriptor, method)
val signature = signatureSerializer.methodSignature(descriptor, descriptor.name, method)
if (signature != null) {
proto.setExtension(JvmProtoBuf.constructorSignature, signature)
}
@@ -178,7 +179,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
) {
val method = getBinding(METHOD_FOR_FUNCTION, descriptor)
if (method != null) {
val signature = SignatureSerializer().methodSignature(descriptor, method)
val signature = signatureSerializer.methodSignature(descriptor, descriptor.name, method)
if (signature != null) {
proto.setExtension(JvmProtoBuf.methodSignature, signature)
}
@@ -232,8 +233,6 @@ class JvmSerializerExtension @JvmOverloads constructor(
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: DescriptorSerializer
) {
val signatureSerializer = SignatureSerializer()
val getter = descriptor.getter
val setter = descriptor.setter
val getterMethod = if (getter == null) null else getBinding(METHOD_FOR_FUNCTION, getter)
@@ -245,13 +244,14 @@ class JvmSerializerExtension @JvmOverloads constructor(
assert(descriptor.isDelegated || delegateMethod == null) { "non-delegated property $descriptor has delegate method" }
val signature = signatureSerializer.propertySignature(
descriptor,
descriptor.name,
field?.second,
field?.first?.descriptor,
if (syntheticMethod != null) signatureSerializer.methodSignature(null, syntheticMethod) else null,
if (delegateMethod != null) signatureSerializer.methodSignature(null, delegateMethod) else null,
if (getterMethod != null) signatureSerializer.methodSignature(null, getterMethod) else null,
if (setterMethod != null) signatureSerializer.methodSignature(null, setterMethod) else null
if (syntheticMethod != null) signatureSerializer.methodSignature(null, null, syntheticMethod) else null,
if (delegateMethod != null) signatureSerializer.methodSignature(null, null, delegateMethod) else null,
if (getterMethod != null) signatureSerializer.methodSignature(null, null, getterMethod) else null,
if (setterMethod != null) signatureSerializer.methodSignature(null, null, setterMethod) else null,
field?.first?.descriptor?.let { signatureSerializer.requiresPropertySignature(descriptor, it) } ?: false,
)
if (signature != null) {
@@ -295,101 +295,42 @@ class JvmSerializerExtension @JvmOverloads constructor(
private fun <K : Any, V> getBinding(slice: SerializationMappingSlice<K, V>, key: K): V? =
bindings.get(slice, key) ?: globalBindings.get(slice, key)
}
private inner class SignatureSerializer {
fun methodSignature(descriptor: FunctionDescriptor?, method: Method): JvmProtoBuf.JvmMethodSignature? {
val builder = JvmProtoBuf.JvmMethodSignature.newBuilder()
if (descriptor == null || descriptor.name.asString() != method.name) {
builder.name = stringTable.getStringIndex(method.name)
}
if (descriptor == null || requiresSignature(descriptor, method.descriptor)) {
builder.desc = stringTable.getStringIndex(method.descriptor)
}
return if (builder.hasName() || builder.hasDesc()) builder.build() else null
class JvmSignatureSerializerImpl(stringTable: StringTable) : JvmSignatureSerializer<FunctionDescriptor, PropertyDescriptor>(stringTable) {
// We don't write those signatures which can be trivially reconstructed from already serialized data
// TODO: make JvmStringTable implement NameResolver and use JvmProtoBufUtil#getJvmMethodSignature instead
override fun requiresFunctionSignature(descriptor: FunctionDescriptor, desc: String): Boolean {
val sb = StringBuilder()
sb.append("(")
val receiverParameter = descriptor.extensionReceiverParameter
if (receiverParameter != null) {
val receiverDesc = mapTypeDefault(receiverParameter.value.type) ?: return true
sb.append(receiverDesc)
}
// We don't write those signatures which can be trivially reconstructed from already serialized data
// TODO: make JvmStringTable implement NameResolver and use JvmProtoBufUtil#getJvmMethodSignature instead
private fun requiresSignature(descriptor: FunctionDescriptor, desc: String): Boolean {
val sb = StringBuilder()
sb.append("(")
val receiverParameter = descriptor.extensionReceiverParameter
if (receiverParameter != null) {
val receiverDesc = mapTypeDefault(receiverParameter.value.type) ?: return true
sb.append(receiverDesc)
}
for (valueParameter in descriptor.valueParameters) {
val paramDesc = mapTypeDefault(valueParameter.type) ?: return true
sb.append(paramDesc)
}
sb.append(")")
val returnType = descriptor.returnType
val returnTypeDesc = (if (returnType == null) "V" else mapTypeDefault(returnType)) ?: return true
sb.append(returnTypeDesc)
return sb.toString() != desc
for (valueParameter in descriptor.valueParameters) {
val paramDesc = mapTypeDefault(valueParameter.type) ?: return true
sb.append(paramDesc)
}
private fun requiresSignature(descriptor: PropertyDescriptor, desc: String): Boolean {
return desc != mapTypeDefault(descriptor.type)
}
sb.append(")")
private fun mapTypeDefault(type: KotlinType): String? {
val classifier = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
val classId = classifier.classId
return if (classId == null) null else ClassMapperLite.mapClass(classId.asString())
}
val returnType = descriptor.returnType
val returnTypeDesc = (if (returnType == null) "V" else mapTypeDefault(returnType)) ?: return true
sb.append(returnTypeDesc)
fun propertySignature(
descriptor: PropertyDescriptor,
fieldName: String?,
fieldDesc: String?,
syntheticMethod: JvmProtoBuf.JvmMethodSignature?,
delegateMethod: JvmProtoBuf.JvmMethodSignature?,
getter: JvmProtoBuf.JvmMethodSignature?,
setter: JvmProtoBuf.JvmMethodSignature?
): JvmProtoBuf.JvmPropertySignature? {
val signature = JvmProtoBuf.JvmPropertySignature.newBuilder()
return sb.toString() != desc
}
if (fieldDesc != null) {
assert(fieldName != null) { "Field name shouldn't be null when there's a field type: $fieldDesc" }
signature.field = fieldSignature(descriptor, fieldName!!, fieldDesc)
}
override fun requiresPropertySignature(descriptor: PropertyDescriptor, desc: String): Boolean {
return desc != mapTypeDefault(descriptor.type)
}
if (syntheticMethod != null) {
signature.syntheticMethod = syntheticMethod
}
if (delegateMethod != null) {
signature.delegateMethod = delegateMethod
}
if (getter != null) {
signature.getter = getter
}
if (setter != null) {
signature.setter = setter
}
return signature.build().takeIf { it.serializedSize > 0 }
}
fun fieldSignature(
descriptor: PropertyDescriptor,
name: String,
desc: String
): JvmProtoBuf.JvmFieldSignature {
val builder = JvmProtoBuf.JvmFieldSignature.newBuilder()
if (descriptor.name.asString() != name) {
builder.name = stringTable.getStringIndex(name)
}
if (requiresSignature(descriptor, desc)) {
builder.desc = stringTable.getStringIndex(desc)
}
return builder.build()
}
private fun mapTypeDefault(type: KotlinType): String? {
val classifier = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
val classId = classifier.classId
return if (classId == null) null else ClassMapperLite.mapClass(classId.asString())
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.serialization
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.serialization.StringTable
import org.jetbrains.kotlin.name.Name
import org.jetbrains.org.objectweb.asm.commons.Method
abstract class JvmSignatureSerializer<F, P>(val stringTable: StringTable) {
fun methodSignature(descriptor: F?, descriptorName: Name?, method: Method): JvmProtoBuf.JvmMethodSignature? {
val builder = JvmProtoBuf.JvmMethodSignature.newBuilder()
if (descriptor == null || descriptorName?.asString() != method.name) {
builder.name = stringTable.getStringIndex(method.name)
}
if (descriptor == null || requiresFunctionSignature(descriptor, method.descriptor)) {
builder.desc = stringTable.getStringIndex(method.descriptor)
}
return if (builder.hasName() || builder.hasDesc()) builder.build() else null
}
protected abstract fun requiresFunctionSignature(descriptor: F, desc: String): Boolean
abstract fun requiresPropertySignature(descriptor: P, desc: String): Boolean
fun propertySignature(
descriptorName: Name,
fieldName: String?,
fieldDesc: String?,
syntheticMethod: JvmProtoBuf.JvmMethodSignature?,
delegateMethod: JvmProtoBuf.JvmMethodSignature?,
getter: JvmProtoBuf.JvmMethodSignature?,
setter: JvmProtoBuf.JvmMethodSignature?,
requiresFieldSignature: Boolean
): JvmProtoBuf.JvmPropertySignature? {
val signature = JvmProtoBuf.JvmPropertySignature.newBuilder()
if (fieldDesc != null) {
assert(fieldName != null) { "Field name shouldn't be null when there's a field type: $fieldDesc" }
signature.field = fieldSignature(descriptorName, fieldName!!, fieldDesc, requiresFieldSignature, stringTable)
}
if (syntheticMethod != null) {
signature.syntheticMethod = syntheticMethod
}
if (delegateMethod != null) {
signature.delegateMethod = delegateMethod
}
if (getter != null) {
signature.getter = getter
}
if (setter != null) {
signature.setter = setter
}
return signature.build().takeIf { it.serializedSize > 0 }
}
private fun fieldSignature(
propertyName: Name,
fieldName: String,
fieldDesc: String,
requiresFieldSignature: Boolean,
stringTable: StringTable
): JvmProtoBuf.JvmFieldSignature {
val builder = JvmProtoBuf.JvmFieldSignature.newBuilder()
if (propertyName.asString() != fieldName) {
builder.name = stringTable.getStringIndex(fieldName)
}
if (requiresFieldSignature) {
builder.desc = stringTable.getStringIndex(fieldDesc)
}
return builder.build()
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.backend.jvm
import org.jetbrains.kotlin.backend.jvm.mapping.IrTypeMapper
import org.jetbrains.kotlin.codegen.ClassBuilderMode
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
import org.jetbrains.kotlin.codegen.serialization.JvmSignatureSerializer
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.descriptors.ClassKind
@@ -63,6 +64,7 @@ class FirJvmSerializerExtension(
override val constValueProvider: ConstValueProvider?,
override val additionalAnnotationsProvider: FirAdditionalMetadataAnnotationsProvider?,
) : FirSerializerExtension() {
private val signatureSerializer = FirJvmSignatureSerializer(stringTable)
constructor(
session: FirSession,
@@ -187,7 +189,7 @@ class FirJvmSerializerExtension(
) {
val method = getBinding(METHOD_FOR_FIR_FUNCTION, constructor)
if (method != null) {
val signature = SignatureSerializer().methodSignature(constructor, method)
val signature = signatureSerializer.methodSignature(constructor, null, method)
if (signature != null) {
proto.setExtension(JvmProtoBuf.constructorSignature, signature)
}
@@ -202,7 +204,7 @@ class FirJvmSerializerExtension(
) {
val method = getBinding(METHOD_FOR_FIR_FUNCTION, function)
if (method != null) {
val signature = SignatureSerializer().methodSignature(function, method)
val signature = signatureSerializer.methodSignature(function, (function as? FirSimpleFunction)?.name, method)
if (signature != null) {
proto.setExtension(JvmProtoBuf.methodSignature, signature)
}
@@ -233,8 +235,6 @@ class FirJvmSerializerExtension(
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: FirElementSerializer
) {
val signatureSerializer = SignatureSerializer()
val getter = property.getter
val setter = property.setter
val getterMethod = if (getter == null) null else getBinding(METHOD_FOR_FIR_FUNCTION, getter)
@@ -246,13 +246,14 @@ class FirJvmSerializerExtension(
assert(property.delegate != null || delegateMethod == null) { "non-delegated property ${property.render()} has delegate method" }
val signature = signatureSerializer.propertySignature(
property,
property.name,
field?.second,
field?.first?.descriptor,
if (syntheticMethod != null) signatureSerializer.methodSignature(null, syntheticMethod) else null,
if (delegateMethod != null) signatureSerializer.methodSignature(null, delegateMethod) else null,
if (getterMethod != null) signatureSerializer.methodSignature(null, getterMethod) else null,
if (setterMethod != null) signatureSerializer.methodSignature(null, setterMethod) else null
if (syntheticMethod != null) signatureSerializer.methodSignature(null, null, syntheticMethod) else null,
if (delegateMethod != null) signatureSerializer.methodSignature(null, null, delegateMethod) else null,
if (getterMethod != null) signatureSerializer.methodSignature(null, null, getterMethod) else null,
if (setterMethod != null) signatureSerializer.methodSignature(null, null, setterMethod) else null,
requiresFieldSignature = field?.first?.descriptor?.let { signatureSerializer.requiresPropertySignature(property, it) } ?: false
)
if (signature != null) {
@@ -297,102 +298,6 @@ class FirJvmSerializerExtension(
private fun <K : Any, V : Any> getBinding(slice: JvmSerializationBindings.SerializationMappingSlice<K, V>, key: K): V? =
bindings.get(slice, key) ?: globalBindings.get(slice, key)
private inner class SignatureSerializer {
fun methodSignature(function: FirFunction?, method: Method): JvmProtoBuf.JvmMethodSignature? {
val builder = JvmProtoBuf.JvmMethodSignature.newBuilder()
if (function == null || (function as? FirSimpleFunction)?.name?.asString() != method.name) {
builder.name = stringTable.getStringIndex(method.name)
}
if (function == null || requiresSignature(function, method.descriptor)) {
builder.desc = stringTable.getStringIndex(method.descriptor)
}
return if (builder.hasName() || builder.hasDesc()) builder.build() else null
}
// We don't write those signatures which can be trivially reconstructed from already serialized data
// TODO: make JvmStringTable implement NameResolver and use JvmProtoBufUtil#getJvmMethodSignature instead
private fun requiresSignature(function: FirFunction, desc: String): Boolean {
val sb = StringBuilder()
sb.append("(")
val receiverTypeRef = function.receiverParameter?.typeRef
if (receiverTypeRef != null) {
val receiverDesc = mapTypeDefault(receiverTypeRef) ?: return true
sb.append(receiverDesc)
}
for (valueParameter in function.valueParameters) {
val paramDesc = mapTypeDefault(valueParameter.returnTypeRef) ?: return true
sb.append(paramDesc)
}
sb.append(")")
val returnTypeRef = function.returnTypeRef
val returnTypeDesc = (mapTypeDefault(returnTypeRef)) ?: return true
sb.append(returnTypeDesc)
return sb.toString() != desc
}
private fun requiresSignature(property: FirProperty, desc: String): Boolean {
return desc != mapTypeDefault(property.returnTypeRef)
}
private fun mapTypeDefault(typeRef: FirTypeRef): String? {
val classId = typeRef.coneTypeSafe<ConeClassLikeType>()?.classId
return if (classId == null) null else ClassMapperLite.mapClass(classId.asString())
}
fun propertySignature(
property: FirProperty,
fieldName: String?,
fieldDesc: String?,
syntheticMethod: JvmProtoBuf.JvmMethodSignature?,
delegateMethod: JvmProtoBuf.JvmMethodSignature?,
getter: JvmProtoBuf.JvmMethodSignature?,
setter: JvmProtoBuf.JvmMethodSignature?
): JvmProtoBuf.JvmPropertySignature? {
val signature = JvmProtoBuf.JvmPropertySignature.newBuilder()
if (fieldDesc != null) {
assert(fieldName != null) { "Field name shouldn't be null when there's a field type: $fieldDesc" }
signature.field = fieldSignature(property, fieldName!!, fieldDesc)
}
if (syntheticMethod != null) {
signature.syntheticMethod = syntheticMethod
}
if (delegateMethod != null) {
signature.delegateMethod = delegateMethod
}
if (getter != null) {
signature.getter = getter
}
if (setter != null) {
signature.setter = setter
}
return signature.build().takeIf { it.serializedSize > 0 }
}
fun fieldSignature(
property: FirProperty,
name: String,
desc: String
): JvmProtoBuf.JvmFieldSignature {
val builder = JvmProtoBuf.JvmFieldSignature.newBuilder()
if (property.name.asString() != name) {
builder.name = stringTable.getStringIndex(name)
}
if (requiresSignature(property, desc)) {
builder.desc = stringTable.getStringIndex(desc)
}
return builder.build()
}
}
companion object {
val METHOD_FOR_FIR_FUNCTION = JvmSerializationBindings.SerializationMappingSlice.create<FirFunction, Method>()
val FIELD_FOR_PROPERTY = JvmSerializationBindings.SerializationMappingSlice.create<FirProperty, Pair<Type, String>>()
@@ -404,3 +309,39 @@ class FirJvmSerializerExtension(
private val JVM_DEFAULT_WITH_COMPATIBILITY_CLASS_ID = ClassId.topLevel(JVM_DEFAULT_WITH_COMPATIBILITY_FQ_NAME)
}
}
class FirJvmSignatureSerializer(stringTable: FirElementAwareStringTable) : JvmSignatureSerializer<FirFunction, FirProperty>(stringTable) {
// We don't write those signatures which can be trivially reconstructed from already serialized data
// TODO: make JvmStringTable implement NameResolver and use JvmProtoBufUtil#getJvmMethodSignature instead
override fun requiresFunctionSignature(descriptor: FirFunction, desc: String): Boolean {
val sb = StringBuilder()
sb.append("(")
val receiverTypeRef = descriptor.receiverParameter?.typeRef
if (receiverTypeRef != null) {
val receiverDesc = mapTypeDefault(receiverTypeRef) ?: return true
sb.append(receiverDesc)
}
for (valueParameter in descriptor.valueParameters) {
val paramDesc = mapTypeDefault(valueParameter.returnTypeRef) ?: return true
sb.append(paramDesc)
}
sb.append(")")
val returnTypeRef = descriptor.returnTypeRef
val returnTypeDesc = (mapTypeDefault(returnTypeRef)) ?: return true
sb.append(returnTypeDesc)
return sb.toString() != desc
}
override fun requiresPropertySignature(descriptor: FirProperty, desc: String): Boolean {
return desc != mapTypeDefault(descriptor.returnTypeRef)
}
private fun mapTypeDefault(typeRef: FirTypeRef): String? {
val classId = typeRef.coneTypeSafe<ConeClassLikeType>()?.classId
return if (classId == null) null else ClassMapperLite.mapClass(classId.asString())
}
}