Refactor metadata serialization for using after frontend

for "tight" IC cycle
This commit is contained in:
Ilya Chernikov
2021-12-15 09:01:03 +01:00
committed by teamcity
parent 5cca01a7d2
commit 3ca4fe5f9e
9 changed files with 393 additions and 267 deletions
@@ -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, JvmMetadataVersion>(LanguageVersion::class.java).apply {
val LANGUAGE_TO_METADATA_VERSION = EnumMap<LanguageVersion, JvmMetadataVersion>(LanguageVersion::class.java).apply {
val oldMetadataVersion = JvmMetadataVersion(1, 1, 18)
this[KOTLIN_1_0] = oldMetadataVersion
this[KOTLIN_1_1] = oldMetadataVersion
@@ -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 =
@@ -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<FirProperty>,
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<FirProperty>,
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<MessageType, List<ProtoBuf.Property>>
) {
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)
}
}
@@ -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<FirTypeParameter>): 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<FirTypeParameter>) {
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<FirTypeParameter>())
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<MessageLite, JvmStringTable>? {
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<Type, String>) {
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<FirTypeParameter>())
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<FirTypeParameter>,
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<FirTypeParameter>) {
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
}
}
@@ -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))
}
}
@@ -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<String>
) : NameResolver {
private val localNameIndices = types.localNameList.run { if (isEmpty()) emptySet() else toSet() }
strings: Array<String>
) : 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<Record> = ArrayList<Record>().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<Record>.toExpandedRecordsList(): List<Record> =
ArrayList<Record>().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]
}
}
@@ -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<String>,
private val localNameIndices: Set<Int>,
private val records: List<Record>
) : 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]
}
}
@@ -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()
)
}
@@ -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
}
}