Refactor metadata serialization for using after frontend
for "tight" IC cycle
This commit is contained in:
@@ -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
|
||||
|
||||
+1
-1
@@ -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 =
|
||||
|
||||
+33
-17
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+223
-142
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
+15
-102
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
+105
@@ -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]
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user