From 3ca4fe5f9e656f72381584a9283e4321af6fd914 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Wed, 15 Dec 2021 09:01:03 +0100 Subject: [PATCH] Refactor metadata serialization for using after frontend for "tight" IC cycle --- .../kotlin/codegen/state/GenerationState.kt | 2 +- .../fir/backend/jvm/FirJvmBackendExtension.kt | 2 +- .../backend/jvm/FirJvmSerializerExtension.kt | 50 ++- .../fir/backend/jvm/FirMetadataSerializer.kt | 365 +++++++++++------- .../serialization/jvm/JvmNameResolverTest.kt | 3 +- .../jvm/deserialization/JvmNameResolver.kt | 117 +----- .../deserialization/JvmNameResolverBase.kt | 105 +++++ .../jvm/serialization/JvmStringTable.kt | 12 +- .../kotlinx/metadata/test/JarContentTest.kt | 4 +- 9 files changed, 393 insertions(+), 267 deletions(-) create mode 100644 core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolverBase.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index 9d9a5375490..ce143e12356 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -404,7 +404,7 @@ class GenerationState private constructor( classBuilderMode == ClassBuilderMode.LIGHT_CLASSES && origin.originKind in doNotGenerateInLightClassMode companion object { - private val LANGUAGE_TO_METADATA_VERSION = EnumMap(LanguageVersion::class.java).apply { + val LANGUAGE_TO_METADATA_VERSION = EnumMap(LanguageVersion::class.java).apply { val oldMetadataVersion = JvmMetadataVersion(1, 1, 18) this[KOTLIN_1_0] = oldMetadataVersion this[KOTLIN_1_1] = oldMetadataVersion diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmBackendExtension.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmBackendExtension.kt index aed3135418d..2f34aa799c2 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmBackendExtension.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmBackendExtension.kt @@ -24,7 +24,7 @@ class FirJvmBackendExtension(private val session: FirSession, private val compon bindings: JvmSerializationBindings, parentSerializer: MetadataSerializer? ): MetadataSerializer { - return FirMetadataSerializer(session, context, klass, bindings, components, parentSerializer) + return makeFirMetadataSerializerForIrClass(session, context, klass, bindings, components, parentSerializer) } override fun generateMetadataExtraFlags(abiStability: JvmAbiStability?): Int = diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt index 6c6bfdc823d..26c99765e81 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt @@ -19,15 +19,17 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.providers.firProvider -import org.jetbrains.kotlin.fir.types.isBuiltinFunctionalType import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol +import org.jetbrains.kotlin.fir.serialization.FirElementAwareStringTable import org.jetbrains.kotlin.fir.serialization.FirElementSerializer import org.jetbrains.kotlin.fir.serialization.FirSerializerExtension import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.MetadataSource import org.jetbrains.kotlin.load.kotlin.NON_EXISTENT_CLASS_NAME import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmFlags @@ -43,22 +45,36 @@ import org.jetbrains.org.objectweb.asm.commons.Method class FirJvmSerializerExtension( override val session: FirSession, private val bindings: JvmSerializationBindings, - state: GenerationState, - private val irClass: IrClass, + private val metadata: MetadataSource?, private val localDelegatedProperties: List, private val approximator: AbstractTypeApproximator, - typeMapper: IrTypeMapper, - private val components: Fir2IrComponents + private val scopeSession: ScopeSession, + private val globalBindings: JvmSerializationBindings, + private val useTypeTable: Boolean, + private val moduleName: String, + private val classBuilderMode: ClassBuilderMode, + private val isParamAssertionsDisabled: Boolean, + private val unifiedNullChecks: Boolean, + override val metadataVersion: BinaryVersion, + private val jvmDefaultMode: JvmDefaultMode, + override val stringTable: FirElementAwareStringTable ) : FirSerializerExtension() { - private val globalBindings = state.globalSerializationBindings - override val stringTable = FirJvmElementAwareStringTable(typeMapper, components) - private val useTypeTable = state.useTypeTableInSerializer - private val moduleName = state.moduleName - private val classBuilderMode = state.classBuilderMode - private val isParamAssertionsDisabled = state.isParamAssertionsDisabled - private val unifiedNullChecks = state.unifiedNullChecks - override val metadataVersion = state.metadataVersion - private val jvmDefaultMode = state.jvmDefaultMode + + constructor( + session: FirSession, + bindings: JvmSerializationBindings, + state: GenerationState, + metadata: MetadataSource?, + localDelegatedProperties: List, + approximator: AbstractTypeApproximator, + typeMapper: IrTypeMapper, + components: Fir2IrComponents + ) : this( + session, bindings, metadata, localDelegatedProperties, approximator, components.scopeSession, + state.globalSerializationBindings, state.useTypeTableInSerializer, state.moduleName, state.classBuilderMode, + state.isParamAssertionsDisabled, state.unifiedNullChecks, state.metadataVersion, state.jvmDefaultMode, + FirJvmElementAwareStringTable(typeMapper, components) + ) override fun shouldUseTypeTable(): Boolean = useTypeTable override fun shouldSerializeFunction(function: FirFunction): Boolean { @@ -84,7 +100,7 @@ class FirJvmSerializerExtension( versionRequirementTable: MutableVersionRequirementTable, childSerializer: FirElementSerializer ) { - assert((irClass.metadata as FirMetadataSource.Class).fir == klass) + assert((metadata as FirMetadataSource.Class).fir == klass) if (moduleName != JvmProtoBufUtil.DEFAULT_MODULE_NAME) { proto.setExtension(JvmProtoBuf.classModuleName, stringTable.getStringIndex(moduleName)) } @@ -140,7 +156,7 @@ class FirJvmSerializerExtension( extension: GeneratedMessageLite.GeneratedExtension> ) { for (localVariable in localDelegatedProperties) { - val serializer = FirElementSerializer.createForLambda(session, components.scopeSession,this, approximator) + val serializer = FirElementSerializer.createForLambda(session, scopeSession,this, approximator) proto.addExtension(extension, serializer.propertyProto(localVariable)?.build() ?: continue) } } diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt index d972678d838..0240266d929 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt @@ -7,11 +7,17 @@ package org.jetbrains.kotlin.fir.backend.jvm import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.backend.jvm.mapping.IrTypeMapper +import org.jetbrains.kotlin.backend.jvm.mapping.mapClass import org.jetbrains.kotlin.backend.jvm.metadata.MetadataSerializer +import org.jetbrains.kotlin.codegen.ClassBuilderMode import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.backend.Fir2IrComponents import org.jetbrains.kotlin.fir.backend.FirMetadataSource +import org.jetbrains.kotlin.fir.containingClassForLocal import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction import org.jetbrains.kotlin.fir.declarations.builder.buildProperty @@ -19,17 +25,21 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyAccessor import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameterCopy import org.jetbrains.kotlin.fir.diagnostics.ConeIntermediateDiagnostic import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.packageFqName +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.toFirRegularClass +import org.jetbrains.kotlin.fir.serialization.FirElementAwareStringTable import org.jetbrains.kotlin.fir.serialization.FirElementSerializer -import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirDelegateFieldSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.MetadataSource -import org.jetbrains.kotlin.ir.util.getPackageFragment +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable +import org.jetbrains.kotlin.modules.TargetId +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.types.AbstractTypeApproximator import org.jetbrains.kotlin.types.TypeApproximatorConfiguration @@ -37,154 +47,90 @@ import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.Method -class FirMetadataSerializer( - private val session: FirSession, - private val context: JvmBackendContext, - private val irClass: IrClass, - private val serializationBindings: JvmSerializationBindings, +fun makeFirMetadataSerializerForIrClass( + session: FirSession, + context: JvmBackendContext, + irClass: IrClass, + serializationBindings: JvmSerializationBindings, components: Fir2IrComponents, parent: MetadataSerializer? -) : MetadataSerializer { - private val approximator = object : AbstractTypeApproximator(session.typeContext, session.languageVersionSettings) { - override fun createErrorType(debugName: String): SimpleTypeMarker { - return ConeErrorType(ConeIntermediateDiagnostic(debugName)) - } - } - - private fun FirTypeRef.approximated(toSuper: Boolean, typeParameterSet: MutableCollection): FirTypeRef { - val approximatedType = if (toSuper) - approximator.approximateToSuperType(coneType, TypeApproximatorConfiguration.PublicDeclaration) - else - approximator.approximateToSubType(coneType, TypeApproximatorConfiguration.PublicDeclaration) - return withReplacedConeType(approximatedType as? ConeKotlinType).apply { coneType.collectTypeParameters(typeParameterSet) } - } - - private fun ConeKotlinType.collectTypeParameters(c: MutableCollection) { - when (this) { - is ConeFlexibleType -> { - lowerBound.collectTypeParameters(c) - upperBound.collectTypeParameters(c) - } - is ConeClassLikeType -> - for (projection in type.typeArguments) { - if (projection is ConeKotlinTypeProjection) { - projection.type.collectTypeParameters(c) - } - } - is ConeTypeParameterType -> c.add(lookupTag.typeParameterSymbol.fir) - else -> Unit - } - } - - private fun FirFunction.copyToFreeAnonymousFunction(): FirAnonymousFunction { - val function = this - return buildAnonymousFunction { - val typeParameterSet = function.typeParameters.filterIsInstanceTo(mutableSetOf()) - moduleData = function.moduleData - origin = FirDeclarationOrigin.Source - symbol = FirAnonymousFunctionSymbol() - returnTypeRef = function.returnTypeRef.approximated(toSuper = true, typeParameterSet) - receiverTypeRef = function.receiverTypeRef?.approximated(toSuper = false, typeParameterSet) - isLambda = (function as? FirAnonymousFunction)?.isLambda == true - hasExplicitParameterList = (function as? FirAnonymousFunction)?.hasExplicitParameterList == true - valueParameters.addAll(function.valueParameters.map { - buildValueParameterCopy(it) { - returnTypeRef = it.returnTypeRef.approximated(toSuper = false, typeParameterSet) - } - }) - typeParameters += typeParameterSet - } - } - - private fun FirPropertyAccessor.copyToFreeAccessor(): FirPropertyAccessor { - val accessor = this - return buildPropertyAccessor { - val typeParameterSet = accessor.typeParameters.toMutableSet() - moduleData = accessor.moduleData - origin = FirDeclarationOrigin.Source - returnTypeRef = accessor.returnTypeRef.approximated(toSuper = true, typeParameterSet) - symbol = FirPropertyAccessorSymbol() - isGetter = accessor.isGetter - status = accessor.status - accessor.valueParameters.mapTo(valueParameters) { - buildValueParameterCopy(it) { - returnTypeRef = it.returnTypeRef.approximated(toSuper = false, typeParameterSet) - } - } - annotations += accessor.annotations - typeParameters += typeParameterSet - } - } - - private fun FirProperty.copyToFreeProperty(): FirProperty { - val property = this - return buildProperty { - val typeParameterSet = property.typeParameters.toMutableSet() - moduleData = property.moduleData - origin = FirDeclarationOrigin.Source - symbol = FirPropertySymbol(property.symbol.callableId) - returnTypeRef = property.returnTypeRef.approximated(toSuper = true, typeParameterSet) - receiverTypeRef = property.receiverTypeRef?.approximated(toSuper = false, typeParameterSet) - name = property.name - initializer = property.initializer - delegate = property.delegate - delegateFieldSymbol = property.delegateFieldSymbol?.let { - FirDelegateFieldSymbol(it.callableId) - } - getter = property.getter?.copyToFreeAccessor() - setter = property.setter?.copyToFreeAccessor() - isVar = property.isVar - isLocal = property.isLocal - status = property.status - dispatchReceiverType = property.dispatchReceiverType - attributes = property.attributes.copy() - annotations += property.annotations - typeParameters += typeParameterSet - }.apply { - delegateFieldSymbol?.bind(this) - } - } - - private val localDelegatedProperties = context.localDelegatedProperties[irClass.attributeOwnerId]?.map { - (it.owner.metadata as FirMetadataSource.Property).fir.copyToFreeProperty() +): FirMetadataSerializer { + val approximator = TypeApproximatorForMetadataSerializer(session) + val localDelegatedProperties = context.localDelegatedProperties[irClass.attributeOwnerId]?.map { + (it.owner.metadata as FirMetadataSource.Property).fir.copyToFreeProperty(approximator) } ?: emptyList() - - private val serializerExtension = FirJvmSerializerExtension( - session, serializationBindings, context.state, irClass, localDelegatedProperties, approximator, - context.typeMapper, components + val firSerializerExtension = FirJvmSerializerExtension( + session, serializationBindings, context.state, irClass.metadata, localDelegatedProperties, + approximator, context.typeMapper, components ) + return FirMetadataSerializer( + context.state.globalSerializationBindings, + serializationBindings, + firSerializerExtension, + approximator, + makeElementSerializer(irClass.metadata, components.session, components.scopeSession, firSerializerExtension, approximator, parent) + ) +} - private val serializer: FirElementSerializer? = - when (val metadata = irClass.metadata) { - is FirMetadataSource.Class -> FirElementSerializer.create( - components.session, - components.scopeSession, - metadata.fir, serializerExtension, (parent as? FirMetadataSerializer)?.serializer, approximator - ) - is FirMetadataSource.File -> FirElementSerializer.createTopLevel( - components.session, - components.scopeSession, - serializerExtension, - approximator - ) - is FirMetadataSource.Function -> FirElementSerializer.createForLambda( - components.session, - components.scopeSession, - serializerExtension, - approximator - ) - else -> null - } +@OptIn(LookupTagInternals::class) +fun makeLocalFirMetadataSerializerForMetadataSource( + metadata: MetadataSource?, + session: FirSession, + scopeSession: ScopeSession, + globalSerializationBindings: JvmSerializationBindings, + parent: MetadataSerializer?, + targetId: TargetId, + configuration: CompilerConfiguration +): FirMetadataSerializer { + val serializationBindings = JvmSerializationBindings() + val approximator = TypeApproximatorForMetadataSerializer(session) + + val stringTable = object : JvmStringTable(null), FirElementAwareStringTable { + override fun getLocalClassIdReplacement(firClass: FirClass): ClassId = + ((firClass as? FirRegularClass)?.containingClassForLocal()?.toFirRegularClass(session) ?: firClass) + .symbol.classId + } + + val firSerializerExtension = FirJvmSerializerExtension( + session, serializationBindings, metadata, emptyList(), approximator, scopeSession, + globalSerializationBindings, + configuration.getBoolean(JVMConfigurationKeys.USE_TYPE_TABLE), + targetId.name, + ClassBuilderMode.ABI, + configuration.getBoolean(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS), + session.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 && + !configuration.getBoolean(JVMConfigurationKeys.NO_UNIFIED_NULL_CHECKS), + configuration.get(CommonConfigurationKeys.METADATA_VERSION) + ?: GenerationState.LANGUAGE_TO_METADATA_VERSION.getValue(session.languageVersionSettings.languageVersion), + session.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode), + stringTable + ) + return FirMetadataSerializer( + globalSerializationBindings, + serializationBindings, + firSerializerExtension, + approximator, + makeElementSerializer(metadata, session, scopeSession, firSerializerExtension, approximator, parent) + ) +} + +class FirMetadataSerializer( + private val globalSerializationBindings: JvmSerializationBindings, + private val serializationBindings: JvmSerializationBindings, + private val serializerExtension: FirJvmSerializerExtension, + private val approximator: AbstractTypeApproximator, + internal val serializer: FirElementSerializer? +) : MetadataSerializer { override fun serialize(metadata: MetadataSource): Pair? { val message = when (metadata) { is FirMetadataSource.Class -> serializer!!.classProto(metadata.fir).build() is FirMetadataSource.File -> - serializer!!.packagePartProto(irClass.getPackageFragment()!!.fqName, metadata.fir).apply { + serializer!!.packagePartProto(metadata.fir.packageFqName, metadata.fir).apply { serializerExtension.serializeJvmPackage(this) }.build() is FirMetadataSource.Function -> { - val withTypeParameters = metadata.fir.copyToFreeAnonymousFunction() + val withTypeParameters = metadata.fir.copyToFreeAnonymousFunction(approximator) serializationBindings.get(FirJvmSerializerExtension.METHOD_FOR_FIR_FUNCTION, metadata.fir)?.let { serializationBindings.put(FirJvmSerializerExtension.METHOD_FOR_FIR_FUNCTION, withTypeParameters, it) } @@ -204,7 +150,7 @@ class FirMetadataSerializer( FirJvmSerializerExtension.DELEGATE_METHOD_FOR_FIR_VARIABLE else -> throw IllegalStateException("invalid origin $origin for property-related method $signature") } - context.state.globalSerializationBindings.put(slice, fir, signature) + globalSerializationBindings.put(slice, fir, signature) } override fun bindMethodMetadata(metadata: MetadataSource.Function, signature: Method) { @@ -214,6 +160,141 @@ class FirMetadataSerializer( override fun bindFieldMetadata(metadata: MetadataSource.Property, signature: Pair) { val fir = (metadata as FirMetadataSource.Property).fir - context.state.globalSerializationBindings.put(FirJvmSerializerExtension.FIELD_FOR_PROPERTY, fir, signature) + globalSerializationBindings.put(FirJvmSerializerExtension.FIELD_FOR_PROPERTY, fir, signature) + } +} + +internal fun makeElementSerializer( + metadata: MetadataSource?, + session: FirSession, + scopeSession: ScopeSession, + serializerExtension: FirJvmSerializerExtension, + approximator: AbstractTypeApproximator, + parent: MetadataSerializer? +): FirElementSerializer? = + when (metadata) { + is FirMetadataSource.Class -> FirElementSerializer.create( + session, scopeSession, + metadata.fir, + serializerExtension, + (parent as? FirMetadataSerializer)?.serializer, + approximator + ) + is FirMetadataSource.File -> FirElementSerializer.createTopLevel( + session, scopeSession, + serializerExtension, + approximator + ) + is FirMetadataSource.Function -> FirElementSerializer.createForLambda( + session, scopeSession, + serializerExtension, + approximator + ) + else -> null + } + +internal class TypeApproximatorForMetadataSerializer(session: FirSession) : + AbstractTypeApproximator(session.typeContext, session.languageVersionSettings) { + + override fun createErrorType(debugName: String): SimpleTypeMarker { + return ConeErrorType(ConeIntermediateDiagnostic(debugName)) + } +} + +private fun FirFunction.copyToFreeAnonymousFunction(approximator: AbstractTypeApproximator): FirAnonymousFunction { + val function = this + return buildAnonymousFunction { + val typeParameterSet = function.typeParameters.filterIsInstanceTo(mutableSetOf()) + moduleData = function.moduleData + origin = FirDeclarationOrigin.Source + symbol = FirAnonymousFunctionSymbol() + returnTypeRef = function.returnTypeRef.approximated(approximator, typeParameterSet, toSuper = true) + receiverTypeRef = function.receiverTypeRef?.approximated(approximator, typeParameterSet, toSuper = false) + isLambda = (function as? FirAnonymousFunction)?.isLambda == true + hasExplicitParameterList = (function as? FirAnonymousFunction)?.hasExplicitParameterList == true + valueParameters.addAll(function.valueParameters.map { + buildValueParameterCopy(it) { + returnTypeRef = it.returnTypeRef.approximated(approximator, typeParameterSet, toSuper = false) + } + }) + typeParameters += typeParameterSet + } +} + +private fun FirPropertyAccessor.copyToFreeAccessor(approximator: AbstractTypeApproximator): FirPropertyAccessor { + val accessor = this + return buildPropertyAccessor { + val typeParameterSet = accessor.typeParameters.toMutableSet() + moduleData = accessor.moduleData + origin = FirDeclarationOrigin.Source + returnTypeRef = accessor.returnTypeRef.approximated(approximator, typeParameterSet, toSuper = true) + symbol = FirPropertyAccessorSymbol() + isGetter = accessor.isGetter + status = accessor.status + accessor.valueParameters.mapTo(valueParameters) { + buildValueParameterCopy(it) { + returnTypeRef = it.returnTypeRef.approximated(approximator, typeParameterSet, toSuper = false) + } + } + annotations += accessor.annotations + typeParameters += typeParameterSet + } +} + +internal fun FirProperty.copyToFreeProperty(approximator: AbstractTypeApproximator): FirProperty { + val property = this + return buildProperty { + val typeParameterSet = property.typeParameters.toMutableSet() + moduleData = property.moduleData + origin = FirDeclarationOrigin.Source + symbol = FirPropertySymbol(property.symbol.callableId) + returnTypeRef = property.returnTypeRef.approximated(approximator, typeParameterSet, toSuper = true) + receiverTypeRef = property.receiverTypeRef?.approximated(approximator, typeParameterSet, toSuper = false) + name = property.name + initializer = property.initializer + delegate = property.delegate + delegateFieldSymbol = property.delegateFieldSymbol?.let { + FirDelegateFieldSymbol(it.callableId) + } + getter = property.getter?.copyToFreeAccessor(approximator) + setter = property.setter?.copyToFreeAccessor(approximator) + isVar = property.isVar + isLocal = property.isLocal + status = property.status + dispatchReceiverType = property.dispatchReceiverType + attributes = property.attributes.copy() + annotations += property.annotations + typeParameters += typeParameterSet + }.apply { + delegateFieldSymbol?.bind(this) + } +} + +internal fun FirTypeRef.approximated( + approximator: AbstractTypeApproximator, + typeParameterSet: MutableCollection, + toSuper: Boolean +): FirTypeRef { + val approximatedType = if (toSuper) + approximator.approximateToSuperType(coneType, TypeApproximatorConfiguration.PublicDeclaration) + else + approximator.approximateToSubType(coneType, TypeApproximatorConfiguration.PublicDeclaration) + return withReplacedConeType(approximatedType as? ConeKotlinType).apply { coneType.collectTypeParameters(typeParameterSet) } +} + +private fun ConeKotlinType.collectTypeParameters(c: MutableCollection) { + when (this) { + is ConeFlexibleType -> { + lowerBound.collectTypeParameters(c) + upperBound.collectTypeParameters(c) + } + is ConeClassLikeType -> + for (projection in type.typeArguments) { + if (projection is ConeKotlinTypeProjection) { + projection.type.collectTypeParameters(c) + } + } + is ConeTypeParameterType -> c.add(lookupTag.typeParameterSymbol.fir) + else -> Unit } } diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/jvm/JvmNameResolverTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/jvm/JvmNameResolverTest.kt index 2a57031092b..8334a31cf6b 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/jvm/JvmNameResolverTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/jvm/JvmNameResolverTest.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.* import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolverBase import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.serialization.deserialization.getClassId @@ -81,7 +82,7 @@ class JvmNameResolverTest : KtUsefulTestCase() { } fun testPredefined() { - for ((index, predefined) in JvmNameResolver.PREDEFINED_STRINGS.withIndex()) { + for ((index, predefined) in JvmNameResolverBase.PREDEFINED_STRINGS.withIndex()) { assertEquals("Predefined string failed: $predefined (index $index)", predefined, str("ignored", predefinedIndex = index)) } } diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolver.kt b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolver.kt index 45dfe1d8ea3..ad1dccca91f 100644 --- a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolver.kt +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolver.kt @@ -5,116 +5,29 @@ package org.jetbrains.kotlin.metadata.jvm.deserialization -import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record -import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.* class JvmNameResolver( val types: JvmProtoBuf.StringTableTypes, - val strings: Array -) : NameResolver { - private val localNameIndices = types.localNameList.run { if (isEmpty()) emptySet() else toSet() } + strings: Array +) : JvmNameResolverBase( + strings, + types.localNameList.run { if (isEmpty()) emptySet() else toSet() }, + types.recordList.toExpandedRecordsList() +) - // Here we expand the 'range' field of the Record message for simplicity to a list of records - // Note that as an optimization, range of each expanded record is equal to the original range, not 1. If correct ranges are needed, - // please use the original record representation in [types.recordList]. - private val records: List = ArrayList().apply { - val records = types.recordList - this.ensureCapacity(records.size) - for (record in records) { +// Here we expand the 'range' field of the Record message for simplicity to a list of records +// Note that as an optimization, range of each expanded record is equal to the original range, not 1. If correct ranges are needed, +// please use the original record representation in [types.recordList]. +fun List.toExpandedRecordsList(): List = + ArrayList().also { list -> + list.ensureCapacity(size) + for (record in this) { repeat(record.range) { - this.add(record) + list.add(record) } } - this.trimToSize() + list.trimToSize() } - override fun getString(index: Int): String { - val record = records[index] - - var string = when { - record.hasString() -> record.string - record.hasPredefinedIndex() && record.predefinedIndex in PREDEFINED_STRINGS.indices -> - PREDEFINED_STRINGS[record.predefinedIndex] - else -> strings[index] - } - - if (record.substringIndexCount >= 2) { - val (begin, end) = record.substringIndexList - if (0 <= begin && begin <= end && end <= string.length) { - string = string.substring(begin, end) - } - } - - if (record.replaceCharCount >= 2) { - val (from, to) = record.replaceCharList - string = string.replace(from.toChar(), to.toChar()) - } - - when (record.operation ?: NONE) { - NONE -> { - // Do nothing - } - INTERNAL_TO_CLASS_ID -> { - string = string.replace('$', '.') - } - DESC_TO_CLASS_ID -> { - if (string.length >= 2) { - string = string.substring(1, string.length - 1) - } - string = string.replace('$', '.') - } - } - - return string - } - - override fun getQualifiedClassName(index: Int): String = - getString(index) - - override fun isLocalClassName(index: Int): Boolean = - index in localNameIndices - - companion object { - // Simply "kotlin", but to avoid being renamed by namespace relocation (e.g., Shadow.relocate gradle plugin) - private val kotlin = listOf('k', 'o', 't', 'l', 'i', 'n').joinToString(separator = "") - - val PREDEFINED_STRINGS = listOf( - "$kotlin/Any", - "$kotlin/Nothing", - "$kotlin/Unit", - "$kotlin/Throwable", - "$kotlin/Number", - - "$kotlin/Byte", "$kotlin/Double", "$kotlin/Float", "$kotlin/Int", - "$kotlin/Long", "$kotlin/Short", "$kotlin/Boolean", "$kotlin/Char", - - "$kotlin/CharSequence", - "$kotlin/String", - "$kotlin/Comparable", - "$kotlin/Enum", - - "$kotlin/Array", - "$kotlin/ByteArray", "$kotlin/DoubleArray", "$kotlin/FloatArray", "$kotlin/IntArray", - "$kotlin/LongArray", "$kotlin/ShortArray", "$kotlin/BooleanArray", "$kotlin/CharArray", - - "$kotlin/Cloneable", - "$kotlin/Annotation", - - "$kotlin/collections/Iterable", "$kotlin/collections/MutableIterable", - "$kotlin/collections/Collection", "$kotlin/collections/MutableCollection", - "$kotlin/collections/List", "$kotlin/collections/MutableList", - "$kotlin/collections/Set", "$kotlin/collections/MutableSet", - "$kotlin/collections/Map", "$kotlin/collections/MutableMap", - "$kotlin/collections/Map.Entry", "$kotlin/collections/MutableMap.MutableEntry", - - "$kotlin/collections/Iterator", "$kotlin/collections/MutableIterator", - "$kotlin/collections/ListIterator", "$kotlin/collections/MutableListIterator" - ) - - private val PREDEFINED_STRINGS_MAP = PREDEFINED_STRINGS.withIndex().associateBy({ it.value }, { it.index }) - - fun getPredefinedStringIndex(string: String): Int? = PREDEFINED_STRINGS_MAP[string] - } -} diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolverBase.kt b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolverBase.kt new file mode 100644 index 00000000000..6dbce515585 --- /dev/null +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmNameResolverBase.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2010-2021 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.metadata.jvm.deserialization + +import org.jetbrains.kotlin.metadata.deserialization.NameResolver +import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record +import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.* + +open class JvmNameResolverBase( + val strings: Array, + private val localNameIndices: Set, + private val records: List +) : NameResolver { + + override fun getString(index: Int): String { + val record = records[index] + + var string = when { + record.hasString() -> record.string + record.hasPredefinedIndex() && record.predefinedIndex in PREDEFINED_STRINGS.indices -> + PREDEFINED_STRINGS[record.predefinedIndex] + else -> strings[index] + } + + if (record.substringIndexCount >= 2) { + val (begin, end) = record.substringIndexList + if (0 <= begin && begin <= end && end <= string.length) { + string = string.substring(begin, end) + } + } + + if (record.replaceCharCount >= 2) { + val (from, to) = record.replaceCharList + string = string.replace(from.toChar(), to.toChar()) + } + + when (record.operation ?: NONE) { + NONE -> { + // Do nothing + } + INTERNAL_TO_CLASS_ID -> { + string = string.replace('$', '.') + } + DESC_TO_CLASS_ID -> { + if (string.length >= 2) { + string = string.substring(1, string.length - 1) + } + string = string.replace('$', '.') + } + } + + return string + } + + override fun getQualifiedClassName(index: Int): String = + getString(index) + + override fun isLocalClassName(index: Int): Boolean = + index in localNameIndices + + companion object { + // Simply "kotlin", but to avoid being renamed by namespace relocation (e.g., Shadow.relocate gradle plugin) + private val kotlin = listOf('k', 'o', 't', 'l', 'i', 'n').joinToString(separator = "") + + val PREDEFINED_STRINGS = listOf( + "$kotlin/Any", + "$kotlin/Nothing", + "$kotlin/Unit", + "$kotlin/Throwable", + "$kotlin/Number", + + "$kotlin/Byte", "$kotlin/Double", "$kotlin/Float", "$kotlin/Int", + "$kotlin/Long", "$kotlin/Short", "$kotlin/Boolean", "$kotlin/Char", + + "$kotlin/CharSequence", + "$kotlin/String", + "$kotlin/Comparable", + "$kotlin/Enum", + + "$kotlin/Array", + "$kotlin/ByteArray", "$kotlin/DoubleArray", "$kotlin/FloatArray", "$kotlin/IntArray", + "$kotlin/LongArray", "$kotlin/ShortArray", "$kotlin/BooleanArray", "$kotlin/CharArray", + + "$kotlin/Cloneable", + "$kotlin/Annotation", + + "$kotlin/collections/Iterable", "$kotlin/collections/MutableIterable", + "$kotlin/collections/Collection", "$kotlin/collections/MutableCollection", + "$kotlin/collections/List", "$kotlin/collections/MutableList", + "$kotlin/collections/Set", "$kotlin/collections/MutableSet", + "$kotlin/collections/Map", "$kotlin/collections/MutableMap", + "$kotlin/collections/Map.Entry", "$kotlin/collections/MutableMap.MutableEntry", + + "$kotlin/collections/Iterator", "$kotlin/collections/MutableIterator", + "$kotlin/collections/ListIterator", "$kotlin/collections/MutableListIterator" + ) + + private val PREDEFINED_STRINGS_MAP = PREDEFINED_STRINGS.withIndex().associateBy({ it.value }, { it.index }) + + fun getPredefinedStringIndex(string: String): Int? = PREDEFINED_STRINGS_MAP[string] + } +} diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/serialization/JvmStringTable.kt b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/serialization/JvmStringTable.kt index d9676c752b8..8da33ec0a09 100644 --- a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/serialization/JvmStringTable.kt +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/serialization/JvmStringTable.kt @@ -5,9 +5,12 @@ package org.jetbrains.kotlin.metadata.jvm.serialization +import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolverBase +import org.jetbrains.kotlin.metadata.jvm.deserialization.toExpandedRecordsList import org.jetbrains.kotlin.metadata.serialization.StringTable import java.io.OutputStream @@ -73,7 +76,7 @@ open class JvmStringTable(nameResolver: JvmNameResolver? = null) : StringTable { if (isLocal || '$' in className) { strings.add(className) } else { - val predefinedIndex = JvmNameResolver.getPredefinedStringIndex(className) + val predefinedIndex = JvmNameResolverBase.getPredefinedStringIndex(className) if (predefinedIndex != null) { record.predefinedIndex = predefinedIndex // TODO: move all records with predefined names to the end and do not write associated strings for them (since they are ignored) @@ -98,4 +101,11 @@ open class JvmStringTable(nameResolver: JvmNameResolver? = null) : StringTable { build().writeDelimitedTo(output) } } + + fun toNameResolver(): NameResolver = + JvmNameResolverBase( + strings.toTypedArray(), + localNames, + records.map { it.build() }.toExpandedRecordsList() + ) } diff --git a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/JarContentTest.kt b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/JarContentTest.kt index 39bee9e78b6..fc88f931198 100644 --- a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/JarContentTest.kt +++ b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/JarContentTest.kt @@ -5,7 +5,7 @@ package kotlinx.metadata.test -import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolverBase import org.jetbrains.org.objectweb.asm.ClassReader import org.jetbrains.org.objectweb.asm.ClassReader.SKIP_DEBUG import org.jetbrains.org.objectweb.asm.ClassReader.SKIP_FRAMES @@ -58,6 +58,6 @@ class JarContentTest { listOf("Char", "Byte", "Short", "Int", "Float", "Long", "Double", "String", "Enum") .map { "kotlin/jvm/internal/${it}CompanionObject" } val PREDEFINED_STRINGS = - JvmNameResolver.PREDEFINED_STRINGS + listOf("kotlin/jvm/functions", "kotlin/reflect/KFunction") + INTERNAL_COMPANIONS + JvmNameResolverBase.PREDEFINED_STRINGS + listOf("kotlin/jvm/functions", "kotlin/reflect/KFunction") + INTERNAL_COMPANIONS } }