diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt index e8897e70e3c..c80e1d9851a 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt @@ -21,7 +21,6 @@ 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.ir.util.IrDeserializer import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.backend.common.serialization.KotlinIr.IrStatement.* @@ -44,7 +43,7 @@ abstract class IrModuleDeserializer( val logger: LoggingContext, val builtIns: IrBuiltIns, val symbolTable: SymbolTable -) : IrDeserializer { +) { abstract fun deserializeIrSymbol(proto: KotlinIr.IrSymbol): IrSymbol abstract fun deserializeIrType(proto: KotlinIr.IrTypeIndex): IrType @@ -1102,10 +1101,9 @@ abstract class IrModuleDeserializer( private val allKnownOrigins = IrDeclarationOrigin::class.nestedClasses.toList() + DeclarationFactory.FIELD_FOR_OUTER_THIS::class val originIndex = allKnownOrigins.map { it.objectInstance as IrDeclarationOriginImpl }.associateBy { it.name } - val irrelevantOrigin = object : IrDeclarationOriginImpl("irrelevant") {} fun deserializeIrDeclarationOrigin(proto: KotlinIr.IrDeclarationOrigin) = originIndex[deserializeString(proto.custom)]!! - protected fun deserializeDeclaration(proto: KotlinIr.IrDeclaration, parent: IrDeclarationParent?): IrDeclaration { + public open fun deserializeDeclaration(proto: KotlinIr.IrDeclaration, parent: IrDeclarationParent?): IrDeclaration { val start = proto.coordinates.startOffset val end = proto.coordinates.endOffset @@ -1168,3 +1166,5 @@ abstract class IrModuleDeserializer( return declaration } } + +val irrelevantOrigin = object : IrDeclarationOriginImpl("irrelevant") {} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt index 1f5aec59150..48071acea13 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt @@ -11,176 +11,194 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.* +import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.impl.IrLoopBase -import org.jetbrains.kotlin.ir.symbols.* -import org.jetbrains.kotlin.ir.symbols.impl.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrFileSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl +import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.IrDeserializer import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite.* +import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite.newInstance import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor -import java.io.File abstract class KotlinIrLinker( - logger: LoggingContext, - builtIns: IrBuiltIns, - symbolTable: SymbolTable, - private val forwardModuleDescriptor: ModuleDescriptor?, - val firstKnownBuiltinsIndex: Long) - : IrModuleDeserializer(logger, builtIns, symbolTable), - DescriptorUniqIdAware { + val logger: LoggingContext, + val builtIns: IrBuiltIns, + val symbolTable: SymbolTable, + private val forwardModuleDescriptor: ModuleDescriptor?, + private val firstKnownBuiltinsIndex: Long +) : DescriptorUniqIdAware, IrDeserializer { protected val deserializedSymbols = mutableMapOf() private val reachableTopLevels = mutableSetOf() private val deserializedTopLevels = mutableSetOf() private val forwardDeclarations = mutableSetOf() - private var deserializedModuleDescriptor: ModuleDescriptor? = null - private var deserializedModuleProtoSymbolTables = mutableMapOf() - private var deserializedModuleProtoStringTables = mutableMapOf() - private var deserializedModuleProtoTypeTables = mutableMapOf() - private var deserializedModuleLoops = mutableMapOf, IrLoopBase>() + private val deserializersForModules = mutableMapOf() val resolvedForwardDeclarations = mutableMapOf() - abstract protected val descriptorReferenceDeserializer: DescriptorReferenceDeserializer + inner class IrDeserializerForModule( + private val moduleDescriptor: ModuleDescriptor, + private val moduleProto: KotlinIr.IrModule + ) : IrModuleDeserializer(logger, builtIns, symbolTable) { + + private var moduleLoops = mutableMapOf() + + private fun referenceDeserializedSymbol( + proto: KotlinIr.IrSymbolData, + descriptor: DeclarationDescriptor? + ): IrSymbol = when (proto.kind) { + KotlinIr.IrSymbolKind.ANONYMOUS_INIT_SYMBOL -> + IrAnonymousInitializerSymbolImpl( + descriptor as ClassDescriptor? + ?: WrappedClassDescriptor() + ) + KotlinIr.IrSymbolKind.CLASS_SYMBOL -> + symbolTable.referenceClass( + descriptor as ClassDescriptor? + ?: WrappedClassDescriptor() + ) + KotlinIr.IrSymbolKind.CONSTRUCTOR_SYMBOL -> + symbolTable.referenceConstructor( + descriptor as ClassConstructorDescriptor? + ?: WrappedClassConstructorDescriptor() + ) + KotlinIr.IrSymbolKind.TYPE_PARAMETER_SYMBOL -> + symbolTable.referenceTypeParameter( + descriptor as TypeParameterDescriptor? + ?: WrappedTypeParameterDescriptor() + ) + KotlinIr.IrSymbolKind.ENUM_ENTRY_SYMBOL -> + symbolTable.referenceEnumEntry( + descriptor as ClassDescriptor? + ?: WrappedEnumEntryDescriptor() + ) + KotlinIr.IrSymbolKind.STANDALONE_FIELD_SYMBOL -> + symbolTable.referenceField(WrappedFieldDescriptor()) + + KotlinIr.IrSymbolKind.FIELD_SYMBOL -> + symbolTable.referenceField( + descriptor as PropertyDescriptor? + ?: WrappedPropertyDescriptor() + ) + KotlinIr.IrSymbolKind.FUNCTION_SYMBOL -> + symbolTable.referenceSimpleFunction( + descriptor as FunctionDescriptor? + ?: WrappedSimpleFunctionDescriptor() + ) + KotlinIr.IrSymbolKind.VARIABLE_SYMBOL -> + IrVariableSymbolImpl( + descriptor as VariableDescriptor? + ?: WrappedVariableDescriptor() + ) + KotlinIr.IrSymbolKind.VALUE_PARAMETER_SYMBOL -> + IrValueParameterSymbolImpl( + descriptor as ParameterDescriptor? + ?: WrappedValueParameterDescriptor() + ) + KotlinIr.IrSymbolKind.RECEIVER_PARAMETER_SYMBOL -> + IrValueParameterSymbolImpl( + descriptor as ParameterDescriptor? ?: WrappedReceiverParameterDescriptor() + ) + else -> TODO("Unexpected classifier symbol kind: ${proto.kind}") + } + + override fun deserializeIrSymbol(proto: KotlinIr.IrSymbol): IrSymbol { + val symbolData = moduleProto.symbolTable.getSymbols(proto.index) + return deserializeIrSymbolData(symbolData) + } + + override fun deserializeIrType(proto: KotlinIr.IrTypeIndex): IrType { + val typeData = moduleProto.typeTable.getTypes(proto.index) + return deserializeIrTypeData(typeData) + } + + override fun deserializeString(proto: KotlinIr.String): String = + moduleProto.stringTable.getStrings(proto.index) + + override fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoopBase) = + moduleLoops.getOrPut(loopIndex, loopBuilder) + + private fun deserializeIrSymbolData(proto: KotlinIr.IrSymbolData): IrSymbol { + val key = proto.uniqId.uniqIdKey(moduleDescriptor) + val topLevelKey = proto.topLevelUniqId.uniqIdKey(moduleDescriptor) + + if (!deserializedTopLevels.contains(topLevelKey)) reachableTopLevels.add(topLevelKey) + + val symbol = deserializedSymbols.getOrPut(key) { + val descriptor = if (proto.hasDescriptorReference()) { + deserializeDescriptorReference(proto.descriptorReference) + } else { + null + } + + resolvedForwardDeclarations[key]?.let { + if (!deserializedTopLevels.contains(it)) reachableTopLevels.add(it) // Assuming forward declarations are always top levels. + } + + referenceDeserializedSymbol(proto, descriptor) + } + if (symbol.descriptor is ClassDescriptor && + symbol.descriptor !is WrappedDeclarationDescriptor<*> && + symbol.descriptor.module.isForwardDeclarationModule + ) { + forwardDeclarations.add(symbol) + } + + return symbol + } + + override fun deserializeDescriptorReference(proto: KotlinIr.DescriptorReference) = + descriptorReferenceDeserializer.deserializeDescriptorReference( + deserializeString(proto.packageFqName), + deserializeString(proto.classFqName), + deserializeString(proto.name), + if (proto.hasUniqId()) proto.uniqId.index else null, + isEnumEntry = proto.isEnumEntry, + isEnumSpecial = proto.isEnumSpecial, + isDefaultConstructor = proto.isDefaultConstructor, + isFakeOverride = proto.isFakeOverride, + isGetter = proto.isGetter, + isSetter = proto.isSetter, + isTypeParameter = proto.isTypeParameter + ) + + + override fun getPrimitiveTypeOrNull(symbol: IrClassifierSymbol, hasQuestionMark: Boolean) = + this@KotlinIrLinker.getPrimitiveTypeOrNull(symbol, hasQuestionMark) + } + + protected open fun getPrimitiveTypeOrNull(symbol: IrClassifierSymbol, hasQuestionMark: Boolean): IrSimpleType? = null + + protected abstract val descriptorReferenceDeserializer: DescriptorReferenceDeserializer protected val indexAfterKnownBuiltins = loadKnownBuiltinSymbols() - fun loadKnownBuiltinSymbols(): Long { + private fun loadKnownBuiltinSymbols(): Long { var currentIndex = firstKnownBuiltinsIndex builtIns.knownBuiltins.forEach { require(it is IrFunction) - deserializedSymbols.put(UniqIdKey(null, UniqId(currentIndex, isLocal = false)), it.symbol) + deserializedSymbols[UniqIdKey(null, UniqId(currentIndex, isLocal = false))] = it.symbol assert(symbolTable.referenceSimpleFunction(it.descriptor) == it.symbol) currentIndex++ } return currentIndex } - private fun referenceDeserializedSymbol(proto: KotlinIr.IrSymbolData, descriptor: DeclarationDescriptor?): IrSymbol = when (proto.kind) { - KotlinIr.IrSymbolKind.ANONYMOUS_INIT_SYMBOL -> - IrAnonymousInitializerSymbolImpl( - descriptor as ClassDescriptor? - ?: WrappedClassDescriptor() - ) - KotlinIr.IrSymbolKind.CLASS_SYMBOL -> - symbolTable.referenceClass( - descriptor as ClassDescriptor? - ?: WrappedClassDescriptor() - ) - KotlinIr.IrSymbolKind.CONSTRUCTOR_SYMBOL -> - symbolTable.referenceConstructor( - descriptor as ClassConstructorDescriptor? - ?: WrappedClassConstructorDescriptor() - ) - KotlinIr.IrSymbolKind.TYPE_PARAMETER_SYMBOL -> - symbolTable.referenceTypeParameter( - descriptor as TypeParameterDescriptor? - ?: WrappedTypeParameterDescriptor() - ) - KotlinIr.IrSymbolKind.ENUM_ENTRY_SYMBOL -> - symbolTable.referenceEnumEntry( - descriptor as ClassDescriptor? - ?: WrappedEnumEntryDescriptor() - ) - KotlinIr.IrSymbolKind.STANDALONE_FIELD_SYMBOL -> - symbolTable.referenceField(WrappedFieldDescriptor()) - - KotlinIr.IrSymbolKind.FIELD_SYMBOL -> - symbolTable.referenceField( - descriptor as PropertyDescriptor? - ?: WrappedPropertyDescriptor() - ) - KotlinIr.IrSymbolKind.FUNCTION_SYMBOL -> - symbolTable.referenceSimpleFunction( - descriptor as FunctionDescriptor? - ?: WrappedSimpleFunctionDescriptor() - ) - KotlinIr.IrSymbolKind.VARIABLE_SYMBOL -> - IrVariableSymbolImpl( - descriptor as VariableDescriptor? - ?: WrappedVariableDescriptor() - ) - KotlinIr.IrSymbolKind.VALUE_PARAMETER_SYMBOL -> - IrValueParameterSymbolImpl( - descriptor as ParameterDescriptor? - ?: WrappedValueParameterDescriptor() - ) - KotlinIr.IrSymbolKind.RECEIVER_PARAMETER_SYMBOL -> - IrValueParameterSymbolImpl( - descriptor as ParameterDescriptor? ?: WrappedReceiverParameterDescriptor() - ) - else -> TODO("Unexpected classifier symbol kind: ${proto.kind}") - } - - override fun deserializeIrSymbol(proto: KotlinIr.IrSymbol): IrSymbol { - val symbolData = - deserializedModuleProtoSymbolTables[deserializedModuleDescriptor]!!.getSymbols(proto.index) - return deserializeIrSymbolData(symbolData) - } - - override fun deserializeIrType(proto: KotlinIr.IrTypeIndex): IrType { - val typeData = - deserializedModuleProtoTypeTables[deserializedModuleDescriptor]!!.getTypes(proto.index) - return deserializeIrTypeData(typeData) - } - - override fun deserializeString(proto: KotlinIr.String) = - deserializedModuleProtoStringTables[deserializedModuleDescriptor]!!.getStrings(proto.index) - - override fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoopBase) = - deserializedModuleLoops.getOrPut(deserializedModuleDescriptor!! to loopIndex, loopBuilder) - - fun deserializeIrSymbolData(proto: KotlinIr.IrSymbolData): IrSymbol { - val key = proto.uniqId.uniqIdKey(deserializedModuleDescriptor!!) - val topLevelKey = proto.topLevelUniqId.uniqIdKey(deserializedModuleDescriptor!!) - - if (!deserializedTopLevels.contains(topLevelKey)) reachableTopLevels.add(topLevelKey) - - val symbol = deserializedSymbols.getOrPut(key) { - val descriptor = if (proto.hasDescriptorReference()) { - deserializeDescriptorReference(proto.descriptorReference) - } else { - null - } - - resolvedForwardDeclarations[key]?.let { - if (!deserializedTopLevels.contains(it)) reachableTopLevels.add(it) // Assuming forward declarations are always top levels. - } - - referenceDeserializedSymbol(proto, descriptor) - } - if (symbol.descriptor is ClassDescriptor && - symbol.descriptor !is WrappedDeclarationDescriptor<*> && - symbol.descriptor.module.isForwardDeclarationModule - ) { - forwardDeclarations.add(symbol) - } - - return symbol - } - - override fun deserializeDescriptorReference(proto: KotlinIr.DescriptorReference) = - descriptorReferenceDeserializer.deserializeDescriptorReference( - deserializeString(proto.packageFqName), - deserializeString(proto.classFqName), - deserializeString(proto.name), - if (proto.hasUniqId()) proto.uniqId.index else null, - isEnumEntry = proto.isEnumEntry, - isEnumSpecial = proto.isEnumSpecial, - isDefaultConstructor = proto.isDefaultConstructor, - isFakeOverride = proto.isFakeOverride, - isGetter = proto.isGetter, - isSetter = proto.isSetter, - isTypeParameter = proto.isTypeParameter - ) - private val ByteArray.codedInputStream: org.jetbrains.kotlin.protobuf.CodedInputStream get() { val codedInputStream = org.jetbrains.kotlin.protobuf.CodedInputStream.newInstance(this) @@ -190,13 +208,18 @@ abstract class KotlinIrLinker( private val reversedFileIndex = mutableMapOf() - private val UniqIdKey.moduleOfOrigin get() = - this.moduleDescriptor ?: reversedFileIndex[this]?.packageFragmentDescriptor?.containingDeclaration + private val UniqIdKey.moduleOfOrigin + get() = + this.moduleDescriptor ?: reversedFileIndex[this]?.packageFragmentDescriptor?.containingDeclaration private fun deserializeTopLevelDeclaration(uniqIdKey: UniqIdKey): IrDeclaration { val proto = loadTopLevelDeclarationProto(uniqIdKey) - return deserializeDeclaration(proto, reversedFileIndex[uniqIdKey]!!) + return deserializersForModules[uniqIdKey.moduleOfOrigin]!!.deserializeDeclaration( + proto, + reversedFileIndex[uniqIdKey]!! + ) } + protected abstract fun reader(moduleDescriptor: ModuleDescriptor, uniqId: UniqId): ByteArray private fun loadTopLevelDeclarationProto(uniqIdKey: UniqIdKey): KotlinIr.IrDeclaration { @@ -230,14 +253,14 @@ abstract class KotlinIrLinker( if (deserializedSymbols[key]?.isBound == true || // The key.moduleOrigin is null for uniqIds that we haven't seen in any of the library headers. // Just skip it for now and handle it elsewhere. - key.moduleOfOrigin == null) { + key.moduleOfOrigin == null + ) { reachableTopLevels.remove(key) deserializedTopLevels.add(key) continue } - deserializedModuleDescriptor = key.moduleOfOrigin val reachable = deserializeTopLevelDeclaration(key) val file = reversedFileIndex[key]!! file.declarations.add(reachable) @@ -253,8 +276,7 @@ abstract class KotlinIrLinker( override fun findDeserializedDeclaration(symbol: IrSymbol): IrDeclaration? { if (!symbol.isBound) { - val topLevelDesecriptor = findDeserializedDeclarationForDescriptor(symbol.descriptor) - if (topLevelDesecriptor == null) return null + findDeserializedDeclarationForDescriptor(symbol.descriptor) ?: return null } assert(symbol.isBound) { @@ -291,13 +313,14 @@ abstract class KotlinIrLinker( val declarations = symbols.map { val classDescriptor = it.descriptor as ClassDescriptor - val declaration = symbolTable.declareClass(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, - classDescriptor, - classDescriptor.modality + val declaration = symbolTable.declareClass( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, + classDescriptor, + classDescriptor.modality ) { symbol: IrClassSymbol -> IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, symbol) } - .also { - it.parent = file - } + .also { + it.parent = file + } declaration } @@ -305,14 +328,22 @@ abstract class KotlinIrLinker( } } - fun deserializeIrFile(fileProto: KotlinIr.IrFile, moduleDescriptor: ModuleDescriptor, deseralizationStrategy: DeserializationStrategy): IrFile { + fun deserializeIrFile( + fileProto: KotlinIr.IrFile, + moduleDescriptor: ModuleDescriptor, + deseralizationStrategy: DeserializationStrategy + ): IrFile { + + val moduleDeserializer = deserializersForModules[moduleDescriptor]!! + val fileEntry = NaiveSourceBasedFileEntryImpl( - deserializeString(fileProto.fileEntry.name), + moduleDeserializer.deserializeString(fileProto.fileEntry.name), fileProto.fileEntry.lineStartOffsetsList.toIntArray() ) // TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata. - val fqName = deserializeString(fileProto.fqName).let { if (it == "") FqName.ROOT else FqName(it) } + val fqName = moduleDeserializer.deserializeString(fileProto.fqName) + .let { if (it == "") FqName.ROOT else FqName(it) } val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName) @@ -328,22 +359,23 @@ abstract class KotlinIrLinker( } } - val annotations = deserializeAnnotations(fileProto.annotations) + val annotations = moduleDeserializer.deserializeAnnotations(fileProto.annotations) file.annotations.addAll(annotations) if (deseralizationStrategy == DeserializationStrategy.EXPLICITLY_EXPORTED) - fileProto.explicitlyExportedToCompilerList.forEach { deserializeIrSymbol(it) } + fileProto.explicitlyExportedToCompilerList.forEach { moduleDeserializer.deserializeIrSymbol(it) } return file } - fun deserializeIrModuleHeader(proto: KotlinIr.IrModule, moduleDescriptor: ModuleDescriptor, deserializationStrategy: DeserializationStrategy): IrModuleFragment { + fun deserializeIrModuleHeader( + proto: KotlinIr.IrModule, + moduleDescriptor: ModuleDescriptor, + deserializationStrategy: DeserializationStrategy + ): IrModuleFragment { - deserializedModuleDescriptor = moduleDescriptor - deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable) - deserializedModuleProtoStringTables.put(moduleDescriptor, proto.stringTable) - deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable) + deserializersForModules[moduleDescriptor] = IrDeserializerForModule(moduleDescriptor, proto) val files = proto.fileList.map { deserializeIrFile(it, moduleDescriptor, deserializationStrategy) @@ -353,7 +385,11 @@ abstract class KotlinIrLinker( return module } - fun deserializeIrModuleHeader(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, deserializationStrategy: DeserializationStrategy = DeserializationStrategy.ONLY_REFERENCED): IrModuleFragment { + fun deserializeIrModuleHeader( + moduleDescriptor: ModuleDescriptor, + byteArray: ByteArray, + deserializationStrategy: DeserializationStrategy = DeserializationStrategy.ONLY_REFERENCED + ): IrModuleFragment { val proto = KotlinIr.IrModule.parseFrom(byteArray.codedInputStream, newInstance()) return deserializeIrModuleHeader(proto, moduleDescriptor, deserializationStrategy) }