[K/JS] Rework IR deserialization and lowering phases to consume less memory

This commit is contained in:
Artem Kobzar
2023-04-19 13:10:19 +00:00
committed by Space Team
parent 1ee2d0814c
commit 33c5068b79
134 changed files with 964 additions and 616 deletions
@@ -11,6 +11,7 @@ dependencies {
api(project(":compiler:util"))
implementation(project(":compiler:psi"))
compileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
compileOnly(commonDependency("org.jetbrains.intellij.deps.fastutil:intellij-deps-fastutil"))
compileOnly(intellijCore())
}
@@ -228,14 +228,14 @@ private fun StringBuilder.appendProjectDependencies(
return
}
val incomingDependencyIdToDependencies: MutableMap<ResolvedDependencyId, MutableCollection<ResolvedDependency>> = mutableMapOf()
val incomingDependencyIdToDependencies: MutableMap<ResolvedDependencyId, MutableCollection<ResolvedDependency>> = hashMapOf()
allModules.values.forEach { module ->
module.requestedVersionsByIncomingDependencies.keys.forEach { incomingDependencyId ->
incomingDependencyIdToDependencies.getOrPut(incomingDependencyId) { mutableListOf() } += module
}
}
val renderedModules: MutableSet<ResolvedDependencyId> = mutableSetOf()
val renderedModules: MutableSet<ResolvedDependencyId> = hashSetOf()
var everDependenciesOmitted = false
fun renderModules(modules: Collection<ResolvedDependency>, parentData: Data?) {
@@ -346,7 +346,7 @@ private fun findPotentiallyConflictingOutgoingDependencies(
)
// Reverse dependency index.
val outgoingDependenciesIndex: MutableMap<ResolvedDependencyId, MutableList<OutgoingDependency>> = mutableMapOf()
val outgoingDependenciesIndex: MutableMap<ResolvedDependencyId, MutableList<OutgoingDependency>> = hashMapOf()
allModules.values.forEach { module ->
module.requestedVersionsByIncomingDependencies.forEach { (incomingDependencyId, requestedVersion) ->
@@ -88,10 +88,10 @@ open class UserVisibleIrModulesSupport(externalDependenciesLoader: ExternalDepen
selectedVersion = ResolvedDependencyVersion.EMPTY,
// Assumption: As we don't know for sure which modules the source code module depends on directly and which modules
// it depends on transitively, so let's assume it depends on all modules directly.
requestedVersionsByIncomingDependencies = mutableMapOf(
requestedVersionsByIncomingDependencies = hashMapOf(
ResolvedDependencyId.DEFAULT_SOURCE_CODE_MODULE_ID to ResolvedDependencyVersion.EMPTY
),
artifactPaths = mutableSetOf()
artifactPaths = hashSetOf()
)
val outgoingDependencyIds = deserializer.moduleDependencies.map { getUserVisibleModuleId(it) }
@@ -108,7 +108,7 @@ open class UserVisibleIrModulesSupport(externalDependenciesLoader: ExternalDepen
*/
protected fun mergedModules(deserializers: Collection<IrModuleDeserializer>): MutableMap<ResolvedDependencyId, ResolvedDependency> {
val externalDependencyModulesByNames: Map</* unique name */ String, ResolvedDependency> =
mutableMapOf<String, ResolvedDependency>().apply {
hashMapOf<String, ResolvedDependency>().apply {
externalDependencyModules.forEach { externalDependency ->
externalDependency.id.uniqueNames.forEach { uniqueName ->
this[uniqueName] = externalDependency
@@ -122,7 +122,7 @@ open class UserVisibleIrModulesSupport(externalDependenciesLoader: ExternalDepen
// The build system may express a group of modules where one module is a library KLIB and one or more modules
// are just C-interop KLIBs as a single module with multiple artifacts. We need to expand them so that every particular
// module/artifact will be represented as an individual [ResolvedDependency] instance.
val artifactPathsToOriginModules: MutableMap<ResolvedDependencyArtifactPath, ResolvedDependency> = mutableMapOf()
val artifactPathsToOriginModules: MutableMap<ResolvedDependencyArtifactPath, ResolvedDependency> = hashMapOf()
externalDependencyModules.forEach { originModule ->
originModule.artifactPaths.forEach { artifactPath -> artifactPathsToOriginModules[artifactPath] = originModule }
}
@@ -180,7 +180,7 @@ open class UserVisibleIrModulesSupport(externalDependenciesLoader: ExternalDepen
}
}
return (externalDependencyModules + providedModules).associateByTo(mutableMapOf()) { it.id }
return (externalDependencyModules + providedModules).associateByTo(hashMapOf()) { it.id }
}
protected data class ModuleWithUninitializedDependencies(
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
class FakeOverrideChecker(
private val irMangler: KotlinMangler.IrMangler,
@@ -39,25 +40,25 @@ class FakeOverrideChecker(
val descriptorFakeOverrides = classDescriptor.unsubstitutedMemberScope
.getDescriptorsFiltered(DescriptorKindFilter.CALLABLES)
.asSequence()
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
.filterNot { it.visibility == DescriptorVisibilities.PRIVATE || it.visibility == DescriptorVisibilities.INVISIBLE_FAKE }
val descriptorSignatures = descriptorFakeOverrides
.map { with(descriptorMangler) { it.signatureString(compatibleMode) } }
.sorted()
.toMutableList()
.apply { sort() }
val irFakeOverrides = clazz.declarations
val irFakeOverrides = clazz.declarations.asSequence()
.filterIsInstance<IrOverridableMember>()
.filter { it.isFakeOverride }
irFakeOverrides.forEach {
checkOverriddenSymbols(it)
}
.onEach { checkOverriddenSymbols(it) }
val irSignatures = irFakeOverrides
.map { with(irMangler) { it.signatureString(compatibleMode) } }
.sorted()
.toMutableList()
.apply { sort() }
// We can't have equality here because dependency libraries could have
// been compiled with -friend-modules.
@@ -27,14 +27,18 @@ abstract class BasicIrModuleDeserializer(
override val klib: IrLibrary,
override val strategyResolver: (String) -> DeserializationStrategy,
libraryAbiVersion: KotlinAbiVersion,
private val containsErrorCode: Boolean = false
private val containsErrorCode: Boolean = false,
private val shouldSaveDeserializationState: Boolean = true,
) : IrModuleDeserializer(moduleDescriptor, libraryAbiVersion) {
private val fileToDeserializerMap = mutableMapOf<IrFile, IrFileDeserializer>()
private val moduleDeserializationState = ModuleDeserializationState()
protected val moduleReversedFileIndex = mutableMapOf<IdSignature, FileDeserializationState>()
protected var fileDeserializationStates: List<FileDeserializationState> = emptyList()
get() = if (!shouldSaveDeserializationState) error("File deserialization state are not cached inside the instance because `shouldSaveDeserializationState` was set as `false`") else field
protected val moduleReversedFileIndex = hashMapOf<IdSignature, FileDeserializationState>()
override val moduleDependencies by lazy {
moduleDescriptor.allDependencyModules
@@ -46,8 +50,6 @@ abstract class BasicIrModuleDeserializer(
return fileToDeserializerMap.values.filterNot { strategyResolver(it.file.fileEntry.name).onDemand }
}
protected lateinit var fileDeserializationStates: List<FileDeserializationState>
override fun init(delegate: IrModuleDeserializer) {
val fileCount = klib.fileCount()
@@ -64,7 +66,9 @@ abstract class BasicIrModuleDeserializer(
moduleFragment.files.add(file)
}
this.fileDeserializationStates = fileDeserializationStates
if (shouldSaveDeserializationState) {
this.fileDeserializationStates = fileDeserializationStates
}
fileToDeserializerMap.values.forEach { it.symbolDeserializer.deserializeExpectActualMapping() }
}
@@ -128,7 +132,7 @@ abstract class BasicIrModuleDeserializer(
fileStrategy.needBodies,
allowErrorNodes,
fileStrategy.inlineBodies,
moduleDeserializer
moduleDeserializer,
)
fileToDeserializerMap[file] = fileDeserializationState.fileDeserializer
@@ -32,7 +32,7 @@ abstract class GlobalDeclarationTable(
) {
val publicIdSignatureComputer = PublicIdSignatureComputer(mangler)
protected val table = mutableMapOf<IrDeclaration, IdSignature>()
protected val table = hashMapOf<IrDeclaration, IdSignature>()
constructor(mangler: KotlinMangler.IrMangler) : this(mangler, IdSignatureClashTracker.DEFAULT_TRACKER)
@@ -53,7 +53,7 @@ abstract class GlobalDeclarationTable(
}
open class DeclarationTable(globalTable: GlobalDeclarationTable) {
protected val table = mutableMapOf<IrDeclaration, IdSignature>()
protected val table = hashMapOf<IrDeclaration, IdSignature>()
protected open val globalDeclarationTable: GlobalDeclarationTable = globalTable
// TODO: we need to disentangle signature construction with declaration tables.
open val signaturer: IdSignatureSerializer = IdSignatureSerializer(globalTable.publicIdSignatureComputer, this)
@@ -62,7 +62,7 @@ class ExpectActualTable(val expectDescriptorToSymbol: MutableMap<DeclarationDesc
}
private fun IrDeclaration.recordRightHandSide(): Map<DeclarationDescriptor, IrSymbol> {
val rightHandSide = mutableMapOf<DeclarationDescriptor, IrSymbol>()
val rightHandSide = hashMapOf<DeclarationDescriptor, IrSymbol>()
this.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
@@ -5,9 +5,9 @@
package org.jetbrains.kotlin.backend.common.serialization
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.IdSignature.FileSignature
import org.jetbrains.kotlin.utils.newHashMapWithExpectedSize
import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature
import org.jetbrains.kotlin.backend.common.serialization.proto.CommonIdSignature as ProtoCommonIdSignature
import org.jetbrains.kotlin.backend.common.serialization.proto.CompositeSignature as ProtoCompositeSignature
@@ -18,7 +18,8 @@ import org.jetbrains.kotlin.backend.common.serialization.proto.LocalSignature as
class IdSignatureDeserializer(
private val libraryFile: IrLibraryFile,
private val fileSignature: FileSignature?
private val fileSignature: FileSignature?,
private val internationService: IrInterningService
) {
private fun loadSignatureProto(index: Int): ProtoIdSignature {
@@ -35,8 +36,8 @@ class IdSignatureDeserializer(
}
private fun deserializePublicIdSignature(proto: ProtoCommonIdSignature): IdSignature.CommonSignature {
val pkg = libraryFile.deserializeFqName(proto.packageFqNameList)
val cls = libraryFile.deserializeFqName(proto.declarationFqNameList)
val pkg = internationService.string(libraryFile.deserializeFqName(proto.packageFqNameList))
val cls = internationService.string(libraryFile.deserializeFqName(proto.declarationFqNameList))
val memberId = if (proto.hasMemberUniqId()) proto.memberUniqId else null
return IdSignature.CommonSignature(pkg, cls, memberId, proto.flags)
@@ -49,8 +50,9 @@ class IdSignatureDeserializer(
val hash = proto.accessorHashId
val mask = proto.flags
val declarationFqName = internationService.string("${propertySignature.declarationFqName}.$name")
val accessorSignature =
IdSignature.CommonSignature(propertySignature.packageFqName, "${propertySignature.declarationFqName}.$name", hash, mask)
IdSignature.CommonSignature(propertySignature.packageFqName, declarationFqName, hash, mask)
return IdSignature.AccessorSignature(propertySignature, accessorSignature)
}
@@ -70,7 +72,7 @@ class IdSignatureDeserializer(
}
private fun deserializeLocalIdSignature(proto: ProtoLocalSignature): IdSignature.LocalSignature {
val localFqn = libraryFile.deserializeFqName(proto.localFqNameList)
val localFqn = internationService.string(libraryFile.deserializeFqName(proto.localFqNameList))
val localHash = if (proto.hasLocalHash()) proto.localHash else null
val description = if (proto.hasDebugInfo()) libraryFile.debugInfo(proto.debugInfo) else null
return IdSignature.LocalSignature(localFqn, localHash, description)
@@ -93,6 +95,7 @@ class IdSignatureDeserializer(
}
fun signatureToIndexMapping(): Map<IdSignature, Int> {
return signatureCache.entries.associate { it.value to it.key }
if (signatureCache.isEmpty()) return emptyMap()
return signatureCache.entries.associateTo(newHashMapWithExpectedSize(signatureCache.size)) { it.value to it.key }
}
}
@@ -105,7 +105,7 @@ class CurrentModuleWithICDeserializer(
icReaderFactory: (IrLibrary) -> IrModuleDeserializer) :
IrModuleDeserializer(delegate.moduleDescriptor, KotlinAbiVersion.CURRENT) {
private val dirtyDeclarations = mutableMapOf<IdSignature, IrSymbol>()
private val dirtyDeclarations = hashMapOf<IdSignature, IrSymbol>()
private val icKlib = ICKotlinLibrary(icData)
private val icDeserializer: IrModuleDeserializer = icReaderFactory(icKlib)
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.utils.memoryOptimizedMap
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBlock as ProtoBlock
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBlockBody as ProtoBlockBody
@@ -81,7 +82,7 @@ class IrBodyDeserializer(
private val declarationDeserializer: IrDeclarationDeserializer
) {
private val fileLoops = mutableMapOf<Int, IrLoop>()
private val fileLoops = hashMapOf<Int, IrLoop>()
private fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoop): IrLoop =
fileLoops.getOrPut(loopIndex, loopBuilder)
@@ -90,14 +91,7 @@ class IrBodyDeserializer(
proto: ProtoBlockBody,
start: Int, end: Int
): IrBlockBody {
val statements = mutableListOf<IrStatement>()
val statementProtos = proto.statementList
statementProtos.forEach {
statements.add(deserializeStatement(it) as IrStatement)
}
val statements = proto.statementList.memoryOptimizedMap { deserializeStatement(it) as IrStatement }
return irFactory.createBlockBody(start, end, statements)
}
@@ -163,14 +157,14 @@ class IrBodyDeserializer(
private fun deserializeMemberAccessCommon(access: IrMemberAccessExpression<*>, proto: ProtoMemberAccessCommon) {
proto.valueArgumentList.mapIndexed { i, arg ->
proto.valueArgumentList.forEachIndexed { i, arg ->
if (arg.hasExpression()) {
val expr = deserializeExpression(arg.expression)
access.putValueArgument(i, expr)
}
}
proto.typeArgumentList.mapIndexed { i, arg ->
proto.typeArgumentList.forEachIndexed { i, arg ->
access.putTypeArgument(i, declarationDeserializer.deserializeNullableIrType(arg))
}
@@ -211,16 +205,16 @@ class IrBodyDeserializer(
val klass = constructorCall.symbol.owner.parentAsClass
val typeParameters = extractTypeParameters(klass)
val typeParameters = extractTypeParameters(klass).ifEmpty {
return IrSimpleTypeBuilder().apply { classifier = klass.symbol }.buildSimpleType()
}
val typeArguments = ArrayList<IrTypeArgument>(typeParameters.size)
val typeParameterSymbols = ArrayList<IrTypeParameterSymbol>(typeParameters.size)
val rawType = with(IrSimpleTypeBuilder()) {
arguments = typeParameters.run {
mapTo(ArrayList(size)) {
classifier = it.symbol
buildTypeProjection()
}
arguments = typeParameters.memoryOptimizedMap {
classifier = it.symbol
buildTypeProjection()
}
classifier = klass.symbol
buildSimpleType()
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.*
import kotlin.collections.set
import org.jetbrains.kotlin.backend.common.serialization.proto.IrAnonymousInit as ProtoAnonymousInit
import org.jetbrains.kotlin.backend.common.serialization.proto.IrClass as ProtoClass
@@ -52,9 +53,9 @@ import org.jetbrains.kotlin.backend.common.serialization.proto.IrInlineClassRepr
import org.jetbrains.kotlin.backend.common.serialization.proto.IrLocalDelegatedProperty as ProtoLocalDelegatedProperty
import org.jetbrains.kotlin.backend.common.serialization.proto.IrMultiFieldValueClassRepresentation as ProtoIrMultiFieldValueClassRepresentation
import org.jetbrains.kotlin.backend.common.serialization.proto.IrProperty as ProtoProperty
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSimpleTypeNullability as ProtoSimpleTypeNullablity
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSimpleType as ProtoSimpleType
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSimpleTypeLegacy as ProtoSimpleTypeLegacy
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSimpleTypeNullability as ProtoSimpleTypeNullablity
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement as ProtoStatement
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType as ProtoType
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeAbbreviation as ProtoTypeAbbreviation
@@ -76,27 +77,27 @@ class IrDeclarationDeserializer(
private val platformFakeOverrideClassFilter: FakeOverrideClassFilter,
private val fakeOverrideBuilder: FakeOverrideBuilder,
private val compatibilityMode: CompatibilityMode,
private val partialLinkageEnabled: Boolean
private val partialLinkageEnabled: Boolean,
private val internationService: IrInterningService,
) {
private val bodyDeserializer = IrBodyDeserializer(builtIns, allowErrorNodes, irFactory, libraryFile, this)
private fun deserializeString(index: Int): String {
return libraryFile.string(index)
}
private fun deserializeName(index: Int): Name {
val name = libraryFile.string(index)
return Name.guessByFirstCharacter(name)
return internationService.name(Name.guessByFirstCharacter(deserializeString(index)))
}
private val irTypeCache = mutableMapOf<Int, IrType>()
private fun loadTypeProto(index: Int): ProtoType {
return libraryFile.type(index)
}
private val irTypeCache = hashMapOf<Int, IrType>()
fun deserializeNullableIrType(index: Int): IrType? = if (index == -1) null else deserializeIrType(index)
fun deserializeIrType(index: Int): IrType {
return irTypeCache.getOrPut(index) {
val typeData = loadTypeProto(index)
val typeData = libraryFile.type(index)
deserializeIrTypeData(typeData)
}
}
@@ -110,9 +111,7 @@ class IrDeclarationDeserializer(
}
internal fun deserializeAnnotations(annotations: List<ProtoConstructorCall>): List<IrConstructorCall> {
return annotations.map {
bodyDeserializer.deserializeAnnotation(it)
}
return annotations.memoryOptimizedMap { bodyDeserializer.deserializeAnnotation(it) }
}
private fun deserializeSimpleTypeNullability(proto: ProtoSimpleTypeNullablity) = when (proto) {
@@ -125,8 +124,9 @@ class IrDeclarationDeserializer(
val symbol = deserializeIrSymbolAndRemap(proto.classifier)
.checkSymbolType<IrClassifierSymbol>(fallbackSymbolKind = /* just the first possible option */ CLASS_SYMBOL)
val arguments = proto.argumentList.map { deserializeIrTypeArgument(it) }
val arguments = proto.argumentList.memoryOptimizedMap { deserializeIrTypeArgument(it) }
val annotations = deserializeAnnotations(proto.annotationList)
val abbreviation = if (proto.hasAbbreviation()) deserializeTypeAbbreviation(proto.abbreviation) else null
return IrSimpleTypeImpl(
null,
@@ -134,7 +134,7 @@ class IrDeclarationDeserializer(
deserializeSimpleTypeNullability(proto.nullability),
arguments,
annotations,
if (proto.hasAbbreviation()) deserializeTypeAbbreviation(proto.abbreviation) else null
abbreviation
)
}
@@ -142,8 +142,9 @@ class IrDeclarationDeserializer(
val symbol = deserializeIrSymbolAndRemap(proto.classifier)
.checkSymbolType<IrClassifierSymbol>(fallbackSymbolKind = /* just the first possible option */ CLASS_SYMBOL)
val arguments = proto.argumentList.map { deserializeIrTypeArgument(it) }
val arguments = proto.argumentList.memoryOptimizedMap { deserializeIrTypeArgument(it) }
val annotations = deserializeAnnotations(proto.annotationList)
val abbreviation = if (proto.hasAbbreviation()) deserializeTypeAbbreviation(proto.abbreviation) else null
return IrSimpleTypeImpl(
null,
@@ -151,7 +152,7 @@ class IrDeclarationDeserializer(
SimpleTypeNullability.fromHasQuestionMark(proto.hasQuestionMark),
arguments,
annotations,
if (proto.hasAbbreviation()) deserializeTypeAbbreviation(proto.abbreviation) else null
abbreviation
)
}
@@ -159,13 +160,19 @@ class IrDeclarationDeserializer(
IrTypeAbbreviationImpl(
deserializeIrSymbolAndRemap(proto.typeAlias).checkSymbolType(TYPEALIAS_SYMBOL),
proto.hasQuestionMark,
proto.argumentList.map { deserializeIrTypeArgument(it) },
proto.argumentList.memoryOptimizedMap { deserializeIrTypeArgument(it) },
deserializeAnnotations(proto.annotationList)
)
private val SIMPLE_DYNAMIC_TYPE = IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT)
private fun deserializeDynamicType(proto: ProtoDynamicType): IrDynamicType {
val annotations = deserializeAnnotations(proto.annotationList)
return IrDynamicTypeImpl(null, annotations, Variance.INVARIANT)
return if (proto.annotationCount == 0) {
SIMPLE_DYNAMIC_TYPE
} else {
val annotations = deserializeAnnotations(proto.annotationList)
IrDynamicTypeImpl(null, annotations, Variance.INVARIANT)
}
}
private fun deserializeErrorType(proto: ProtoErrorType): IrErrorType {
@@ -205,7 +212,7 @@ class IrDeclarationDeserializer(
}
// Delegating symbol maps to it's delegate only inside the declaration the symbol belongs to.
private val delegatedSymbolMap = mutableMapOf<IrSymbol, IrSymbol>()
private val delegatedSymbolMap = hashMapOf<IrSymbol, IrSymbol>()
internal fun deserializeIrSymbol(code: Long): IrSymbol {
return symbolDeserializer.deserializeIrSymbol(code)
@@ -367,7 +374,7 @@ class IrDeclarationDeserializer(
}.usingParent {
typeParameters = deserializeTypeParameters(proto.typeParameterList, true)
superTypes = proto.superTypeList.map { deserializeIrType(it) }
superTypes = proto.superTypeList.memoryOptimizedMap { deserializeIrType(it) }
withExternalValue(isExternal) {
val oldDeclarations = declarations.toSet()
@@ -389,8 +396,8 @@ class IrDeclarationDeserializer(
else -> computeMissingInlineClassRepresentationForCompatibility(this)
}
// It has been desided not to deserialize the list of sealed subclasses because of KT-54028
// sealedSubclasses = proto.sealedSubclassList.map { deserializeIrSymbol(it).checkSymbolType(CLASS_SYMBOL) }
// It has been decided not to deserialize the list of sealed subclasses because of KT-54028
// sealedSubclasses = proto.sealedSubclassList.memoryOptimizedMap { deserializeIrSymbol(it).checkSymbolType(CLASS_SYMBOL) }
fakeOverrideBuilder.enqueueClass(this, signature, compatibilityMode)
}
@@ -403,9 +410,9 @@ class IrDeclarationDeserializer(
)
private fun deserializeMultiFieldValueClassRepresentation(proto: ProtoIrMultiFieldValueClassRepresentation): MultiFieldValueClassRepresentation<IrSimpleType> {
val names = proto.underlyingPropertyNameList.map { deserializeName(it) }
val types = proto.underlyingPropertyTypeList.map { deserializeIrType(it) as IrSimpleType }
return MultiFieldValueClassRepresentation(names zip types)
val names = proto.underlyingPropertyNameList.memoryOptimizedMap { deserializeName(it) }
val types = proto.underlyingPropertyTypeList.memoryOptimizedMap { deserializeIrType(it) as IrSimpleType }
return MultiFieldValueClassRepresentation(names memoryOptimizedZip types)
}
private fun computeMissingInlineClassRepresentationForCompatibility(irClass: IrClass): InlineClassRepresentation<IrSimpleType> {
@@ -447,30 +454,17 @@ class IrDeclarationDeserializer(
private fun deserializeTypeParameters(protos: List<ProtoTypeParameter>, isGlobal: Boolean): List<IrTypeParameter> {
// NOTE: fun <C : MutableCollection<in T>, T : Any> Array<out T?>.filterNotNullTo(destination: C): C
val result = ArrayList<IrTypeParameter>(protos.size)
for (index in protos.indices) {
val proto = protos[index]
result.add(deserializeIrTypeParameter(proto, index, isGlobal))
return protos.memoryOptimizedMapIndexed { index, proto ->
deserializeIrTypeParameter(proto, index, isGlobal).apply {
superTypes = proto.superTypeList.memoryOptimizedMap { deserializeIrType(it) }
}
}
for (i in protos.indices) {
result[i].superTypes = protos[i].superTypeList.map { deserializeIrType(it) }
}
return result
}
private fun deserializeValueParameters(protos: List<ProtoValueParameter>): List<IrValueParameter> {
val result = ArrayList<IrValueParameter>(protos.size)
for (i in protos.indices) {
result.add(deserializeIrValueParameter(protos[i], i))
}
return result
return protos.memoryOptimizedMapIndexed { index, proto -> deserializeIrValueParameter(proto, index) }
}
/**
* In `declarations-only` mode in case of private property/function with inferred anonymous private type like this
* class C {
@@ -609,7 +603,7 @@ class IrDeclarationDeserializer(
flags.isFakeOverride
)
}.apply {
overriddenSymbols = proto.overriddenList.map { deserializeIrSymbolAndRemap(it).checkSymbolType(FUNCTION_SYMBOL) }
overriddenSymbols = proto.overriddenList.memoryOptimizedMap { deserializeIrSymbolAndRemap(it).checkSymbolType(FUNCTION_SYMBOL) }
}
}
@@ -74,6 +74,7 @@ class FileDeserializationState(
::addIdSignature,
linker::handleExpectActualMapping,
symbolProcessor = linker.symbolProcessor,
internationService = linker.internationService
) { idSignature, symbolKind ->
linker.deserializeOrReturnUnboundIrSymbolIfPartialLinkageEnabled(idSignature, symbolKind, moduleDeserializer)
}
@@ -91,7 +92,8 @@ class FileDeserializationState(
linker.fakeOverrideBuilder.platformSpecificClassFilter,
linker.fakeOverrideBuilder,
compatibilityMode = moduleDeserializer.compatibilityMode,
linker.partialLinkageSupport.isEnabled
linker.partialLinkageSupport.isEnabled,
internationService = linker.internationService
)
val fileDeserializer = IrFileDeserializer(file, fileReader, fileProto, symbolDeserializer, declarationDeserializer)
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.library.impl.IrMemoryDeclarationWriter
import org.jetbrains.kotlin.library.impl.IrMemoryStringWriter
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
import java.io.File
import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature
import org.jetbrains.kotlin.backend.common.serialization.proto.Actual as ProtoActual
@@ -125,7 +126,7 @@ open class IrFileSerializer(
private val normalizeAbsolutePaths: Boolean = false,
private val sourceBaseDirs: Collection<String>
) {
private val loopIndex = mutableMapOf<IrLoop, Int>()
private val loopIndex = hashMapOf<IrLoop, Int>()
private var currentLoopIndex = 0
// For every actual we keep a corresponding expects' uniqIds.
@@ -134,10 +135,10 @@ open class IrFileSerializer(
// The same type can be used multiple times in a file
// so use this index to store type data only once.
private val protoTypeMap = mutableMapOf<IrTypeKey, Int>()
private val protoTypeMap = hashMapOf<IrTypeKey, Int>()
protected val protoTypeArray = arrayListOf<ProtoType>()
private val protoStringMap = mutableMapOf<String, Int>()
private val protoStringMap = hashMapOf<String, Int>()
protected val protoStringArray = arrayListOf<String>()
// The same signature could be used multiple times in a file
@@ -1444,8 +1445,7 @@ open class IrFileSerializer(
// Make sure that all top level properties are initialized on library's load.
file.declarations
.filterIsInstance<IrProperty>()
.filter { it.backingField?.initializer != null && keepOrderOfProperties(it) }
.filterIsInstanceAnd<IrProperty> { it.backingField?.initializer != null && keepOrderOfProperties(it) }
.forEach {
val fieldSymbol = it.backingField?.symbol ?: error("Not found ID ${it.render()}")
proto.addExplicitlyExportedToCompiler(serializeIrSymbol(fieldSymbol))
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.serialization
import org.jetbrains.kotlin.name.Name
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
/**
* The interface provide an API for interning [String] and [Name] values
* to save memory by eliminating duplicates of instances of those classes
*/
class IrInterningService {
/**
* We use here an open-addressing map, because it consumes at least twice lesser memory than with bucket-based implementation:
* - Open-addressing (cost per entry): ref to key + ref to value
* - Bucket-based (cost per entry): hash code + ref to key + ref to value + ref to the next node + class header with memory alignment
*/
private val strings by lazy { ObjectOpenHashSet<String>() }
private val names by lazy { ObjectOpenHashSet<Name>() }
fun string(string: String): String {
return strings.addOrGet(string)
}
fun name(name: Name): Name {
return names.addOrGet(name)
}
fun clear() {
strings.clear()
names.clear()
}
}
@@ -25,11 +25,12 @@ class IrSymbolDeserializer(
val actuals: List<Actual>,
val enqueueLocalTopLevelDeclaration: (IdSignature) -> Unit,
val handleExpectActualMapping: (IdSignature, IrSymbol) -> IrSymbol,
internationService: IrInterningService,
val symbolProcessor: IrSymbolDeserializer.(IrSymbol, IdSignature) -> IrSymbol = { s, _ -> s },
fileSignature: IdSignature.FileSignature = IdSignature.FileSignature(fileSymbol),
val deserializePublicSymbol: (IdSignature, BinarySymbolData.SymbolKind) -> IrSymbol
) {
val deserializedSymbols: MutableMap<IdSignature, IrSymbol> = mutableMapOf()
val deserializedSymbols: MutableMap<IdSignature, IrSymbol> = hashMapOf()
fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
return deserializedSymbols.getOrPut(idSig) {
@@ -84,7 +85,7 @@ class IrSymbolDeserializer(
}
}
val signatureDeserializer = IdSignatureDeserializer(libraryFile, fileSignature)
val signatureDeserializer = IdSignatureDeserializer(libraryFile, fileSignature, internationService)
fun deserializeIdSignature(index: Int): IdSignature {
return signatureDeserializer.deserializeIdSignature(index)
@@ -15,7 +15,10 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.*
@@ -32,22 +35,23 @@ abstract class KotlinIrLinker(
private val exportedDependencies: List<ModuleDescriptor>,
val symbolProcessor: IrSymbolDeserializer.(IrSymbol, IdSignature) -> IrSymbol = { s, _ -> s },
) : IrDeserializer, FileLocalAwareLinker {
val internationService = IrInterningService()
// Kotlin-MPP related data. Consider some refactoring
val expectIdSignatureToActualIdSignature = mutableMapOf<IdSignature, IdSignature>()
val topLevelActualIdSignatureToModuleDeserializer = mutableMapOf<IdSignature, IrModuleDeserializer>()
internal val expectSymbols = mutableMapOf<IdSignature, IrSymbol>()
internal val actualSymbols = mutableMapOf<IdSignature, IrSymbol>()
val topLevelActualIdSignatureToModuleDeserializer = hashMapOf<IdSignature, IrModuleDeserializer>()
internal val expectSymbols = hashMapOf<IdSignature, IrSymbol>()
internal val actualSymbols = hashMapOf<IdSignature, IrSymbol>()
val modulesWithReachableTopLevels = mutableSetOf<IrModuleDeserializer>()
val modulesWithReachableTopLevels = hashSetOf<IrModuleDeserializer>()
protected val deserializersForModules = mutableMapOf<String, IrModuleDeserializer>()
protected val deserializersForModules = hashMapOf<String, IrModuleDeserializer>()
abstract val fakeOverrideBuilder: FakeOverrideBuilder
abstract val translationPluginContext: TranslationPluginContext?
private val triedToDeserializeDeclarationForSymbol = mutableSetOf<IrSymbol>()
private val triedToDeserializeDeclarationForSymbol = hashSetOf<IrSymbol>()
private lateinit var linkerExtensions: Collection<IrDeserializer.IrLinkerExtension>
@@ -204,6 +208,10 @@ abstract class KotlinIrLinker(
deserializersForModules.values.forEach { it.init() }
}
fun clear() {
internationService.clear()
}
override fun postProcess(inOrAfterLinkageStep: Boolean) {
// TODO: Expect/actual actualization should be fixed to cope with the situation when either expect or actual symbol is unbound.
finalizeExpectActualLinker()
@@ -224,7 +232,6 @@ abstract class KotlinIrLinker(
deserializersForModules.values.asSequence().map { it.moduleFragment }
}
}
// TODO: fix IrPluginContext to make it not produce additional external reference
// symbolTable.noUnboundLeft("unbound after fake overrides:")
}