diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CacheInfoBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CacheInfoBuilder.kt index 35d18882a04..bba6b30af82 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CacheInfoBuilder.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CacheInfoBuilder.kt @@ -12,8 +12,8 @@ import org.jetbrains.kotlin.backend.konan.NativeGenerationState import org.jetbrains.kotlin.backend.konan.KonanFqNames import org.jetbrains.kotlin.backend.konan.isExternalObjCClass import org.jetbrains.kotlin.backend.konan.isFunctionInterfaceFile -import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerIr +import org.jetbrains.kotlin.backend.konan.serialization.KonanPartialModuleDeserializer import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.library.impl.javaFile internal class CacheInfoBuilder( private val generationState: NativeGenerationState, - private val moduleDeserializer: KonanIrLinker.KonanPartialModuleDeserializer, + private val moduleDeserializer: KonanPartialModuleDeserializer, private val irModule: IrModuleFragment ) { fun build() { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrLinker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrLinker.kt index 62ee524de31..93fb3b6bc9c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrLinker.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrLinker.kt @@ -17,9 +17,7 @@ package org.jetbrains.kotlin.backend.konan.serialization import org.jetbrains.kotlin.backend.common.linkage.issues.UserVisibleIrModulesSupport -import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.common.linkage.partial.PartialLinkageSupportForLinker -import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideClassFilter import org.jetbrains.kotlin.backend.common.serialization.* @@ -27,7 +25,6 @@ import org.jetbrains.kotlin.backend.common.serialization.encodings.BinaryNameAnd import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData import org.jetbrains.kotlin.backend.common.serialization.encodings.FunctionFlags import org.jetbrains.kotlin.backend.konan.* -import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder import org.jetbrains.kotlin.backend.konan.descriptors.findPackage import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary @@ -44,10 +41,8 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass -import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol -import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* @@ -60,7 +55,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module import sun.misc.Unsafe import org.jetbrains.kotlin.backend.common.serialization.proto.IrClass as ProtoClass import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration -import org.jetbrains.kotlin.backend.common.serialization.proto.IrField as ProtoField import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunction as ProtoFunction import org.jetbrains.kotlin.backend.common.serialization.proto.IrProperty as ProtoProperty @@ -553,486 +547,6 @@ internal class KonanIrLinker( else -> error("Unknown package fragment kind ${packageFragment::class.java}") } - @OptIn(ObsoleteDescriptorBasedAPI::class) - class KonanPartialModuleDeserializer( - konanIrLinker: KonanIrLinker, - moduleDescriptor: ModuleDescriptor, - override val klib: KotlinLibrary, - private val stubGenerator: DeclarationStubGenerator, - private val cachedLibraries: CachedLibraries, - private val inlineFunctionFiles: MutableMap, - strategyResolver: (String) -> DeserializationStrategy, - private val cacheDeserializationStrategy: CacheDeserializationStrategy, - containsErrorCode: Boolean = false - ) : BasicIrModuleDeserializer(konanIrLinker, moduleDescriptor, klib, - { fileName -> - if (cacheDeserializationStrategy.contains(fileName)) - strategyResolver(fileName) - else DeserializationStrategy.ON_DEMAND - }, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT, containsErrorCode - ) { - private val descriptorSignatures = mutableMapOf() - - val files by lazy { fileDeserializationStates.map { it.file } } - - private val idSignatureToFile by lazy { - buildMap { - fileDeserializationStates.forEach { fileDeserializationState -> - fileDeserializationState.fileDeserializer.reversedSignatureIndex.keys.forEach { idSig -> - put(idSig, fileDeserializationState.file) - } - } - } - } - - private val fileReferenceToFileDeserializationState by lazy { - fileDeserializationStates.associateBy { SerializedFileReference(it.file.packageFqName.asString(), it.file.path) } - } - - private val SerializedFileReference.deserializationState - get() = fileReferenceToFileDeserializationState[this] ?: error("Unknown file $this") - - private tailrec fun IdSignature.fileSignature(): IdSignature.FileSignature? = when (this) { - is IdSignature.FileSignature -> this - is IdSignature.CompositeSignature -> this.container.fileSignature() - else -> null - } - - private val IrClass.firstNonClassParent: IrDeclarationParent - get() { - var parent = parent - while (parent is IrClass) parent = parent.parent - return parent - } - - fun getFileNameOf(declaration: IrDeclaration): String { - fun IrDeclaration.getSignature() = symbol.signature ?: descriptorSignatures[descriptor] - - val idSig = declaration.getSignature() - ?: (declaration.parent as? IrDeclaration)?.getSignature() - ?: ((declaration as? IrAttributeContainer)?.attributeOwnerId as? IrDeclaration)?.getSignature() - ?: error("Can't find signature of ${declaration.render()}") - val topLevelIdSig = idSig.topLevelSignature() - return topLevelIdSig.fileSignature()?.fileName - ?: idSignatureToFile[topLevelIdSig]?.path - ?: error("No file for $idSig") - } - - fun getKlibFileIndexOf(irFile: IrFile) = fileDeserializationStates.first { it.file == irFile }.fileIndex - - fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference { - val signature = irFunction.symbol.signature - ?: error("No signature for ${irFunction.render()}") - val topLevelSignature = signature.topLevelSignature() - val fileDeserializationState = moduleReversedFileIndex[topLevelSignature] - ?: error("No file deserializer for ${topLevelSignature.render()}") - val declarationIndex = fileDeserializationState.fileDeserializer.reversedSignatureIndex[topLevelSignature] - ?: error("No declaration for ${topLevelSignature.render()}") - val fileReader = fileDeserializationState.fileReader - val symbolDeserializer = fileDeserializationState.fileDeserializer.symbolDeserializer - val protoDeclaration = fileReader.declaration(declarationIndex) - - val outerClasses = (irFunction.parent as? IrClass)?.getOuterClasses(takeOnlyInner = false) ?: emptyList() - require((outerClasses.getOrNull(0)?.parent ?: irFunction.parent) is IrFile) { - "Local inline functions are not supported: ${irFunction.render()}" - } - - val typeParameterSigs = mutableListOf() - val outerReceiverSigs = mutableListOf() - val protoFunction = if (outerClasses.isEmpty()) { - val irProperty = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner - if (irProperty == null) - protoDeclaration.irFunction - else protoDeclaration.irProperty.findAccessor(irProperty, irFunction) - } else { - val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner } - var protoClass = protoDeclaration.irClass - outerClasses.indices.forEach { classIndex -> - if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) { - (0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) { - BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId - } - } - if (classIndex < outerClasses.size - 1) { - if (classIndex >= firstNotInnerClassIndex) - outerReceiverSigs.add(BinarySymbolData.decode(protoClass.thisReceiver.base.symbol).signatureId) - protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer) - } - } - protoClass.findInlineFunction(irFunction, fileReader, symbolDeserializer) - } - - val functionSignature = BinarySymbolData.decode(protoFunction.base.base.symbol).signatureId - (0 until protoFunction.base.typeParameterCount).mapTo(typeParameterSigs) { - BinarySymbolData.decode(protoFunction.base.getTypeParameter(it).base.symbol).signatureId - } - val defaultValues = mutableListOf() - val valueParameterSigs = (0 until protoFunction.base.valueParameterCount).map { - val valueParameter = protoFunction.base.getValueParameter(it) - defaultValues.add(if (valueParameter.hasDefaultValue()) valueParameter.defaultValue else INVALID_INDEX) - BinarySymbolData.decode(valueParameter.base.symbol).signatureId - } - val extensionReceiverSig = irFunction.extensionReceiverParameter?.let { - BinarySymbolData.decode(protoFunction.base.extensionReceiver.base.symbol).signatureId - } ?: INVALID_INDEX - val dispatchReceiverSig = irFunction.dispatchReceiverParameter?.let { - BinarySymbolData.decode(protoFunction.base.dispatchReceiver.base.symbol).signatureId - } ?: INVALID_INDEX - - return SerializedInlineFunctionReference(SerializedFileReference(fileDeserializationState.file), - functionSignature, protoFunction.base.body, irFunction.startOffset, irFunction.endOffset, - extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs.toIntArray(), - valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray()) - } - - fun buildClassFields(irClass: IrClass, fields: List): SerializedClassFields { - val signature = irClass.symbol.signature - ?: error("No signature for ${irClass.render()}") - val topLevelSignature = signature.topLevelSignature() - val fileDeserializationState = moduleReversedFileIndex[topLevelSignature] - ?: error("No file deserializer for ${topLevelSignature.render()}") - val fileDeserializer = fileDeserializationState.fileDeserializer - val declarationIndex = fileDeserializer.reversedSignatureIndex[topLevelSignature] - ?: error("No declaration for ${topLevelSignature.render()}") - val fileReader = fileDeserializationState.fileReader - val symbolDeserializer = fileDeserializer.symbolDeserializer - val protoDeclaration = fileReader.declaration(declarationIndex) - - val outerClasses = irClass.getOuterClasses(takeOnlyInner = false) - require(outerClasses.first().parent is IrFile) { "Local classes are not supported: ${irClass.render()}" } - - val typeParameterSigs = mutableListOf() - var protoClass = protoDeclaration.irClass - val protoClasses = mutableListOf(protoClass) - val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner } - for (classIndex in outerClasses.indices) { - if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) { - (0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) { - BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId - } - } - if (classIndex < outerClasses.size - 1) { - protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer) - protoClasses += protoClass - } - } - - val protoFields = mutableListOf() - for (i in 0 until protoClass.declarationCount) { - val declaration = protoClass.getDeclaration(i) - if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_FIELD) - protoFields.add(declaration.irField) - else if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_PROPERTY) { - val protoProperty = declaration.irProperty - if (protoProperty.hasBackingField()) - protoFields.add(protoProperty.backingField) - } - } - val protoFieldsMap = mutableMapOf() - protoFields.forEach { - val nameAndType = BinaryNameAndType.decode(it.nameType) - val name = fileReader.string(nameAndType.nameIndex) - val prev = protoFieldsMap[name] - if (prev != null) - error("Class ${irClass.render()} has two fields with same name '$name'") - protoFieldsMap[name] = it - } - - val outerThisIndex = fields.indexOfFirst { it.irField?.origin == IrDeclarationOrigin.FIELD_FOR_OUTER_THIS } - val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures - return SerializedClassFields( - SerializedFileReference(fileDeserializationState.file), - BinarySymbolData.decode(protoClass.base.symbol).signatureId, - typeParameterSigs.toIntArray(), - outerThisIndex, - Array(fields.size) { - val field = fields[it] - val irField = field.irField ?: error("No IR for field ${field.name} of ${irClass.render()}") - if (it == outerThisIndex) { - require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" } - require(protoClasses.size > 1) { "An inner class must have at least one outer class" } - val outerProtoClass = protoClasses[protoClasses.size - 2] - val nameAndType = BinaryNameAndType.decode(outerProtoClass.thisReceiver.nameType) - - SerializedClassFieldInfo(name = INVALID_INDEX, binaryType = INVALID_INDEX, nameAndType.typeIndex, flags = 0, field.alignment) - } else { - val protoField = protoFieldsMap[field.name] ?: error("No proto for ${irField.render()}") - val nameAndType = BinaryNameAndType.decode(protoField.nameType) - var flags = 0 - if (field.isConst) - flags = flags or SerializedClassFieldInfo.FLAG_IS_CONST - val classifier = irField.type.classifierOrNull - ?: error("Fields of type ${irField.type.render()} are not supported") - val primitiveBinaryType = irField.type.computePrimitiveBinaryTypeOrNull() - - SerializedClassFieldInfo( - nameAndType.nameIndex, - primitiveBinaryType?.ordinal ?: INVALID_INDEX, - if (with(KonanManglerIr) { (classifier as? IrClassSymbol)?.owner?.isExported(compatibleMode) } == false) - INVALID_INDEX - else nameAndType.typeIndex, - flags, - field.alignment - ) - } - }) - } - - fun buildEagerInitializedFile(irFile: IrFile) = - SerializedEagerInitializedFile(SerializedFileReference(irFile)) - - private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl( - moduleDescriptor, KonanManglerDesc, - DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY - ) - - private val deserializedSymbols = mutableMapOf() - - // Need to notify the deserializing machinery that some symbols have already been created by stub generator - // (like type parameters and receiver parameters) and there's no need to create new symbols for them. - private fun referenceIrSymbol(symbolDeserializer: IrSymbolDeserializer, sigIndex: Int, symbol: IrSymbol) { - val idSig = symbolDeserializer.deserializeIdSignature(sigIndex) - symbolDeserializer.referenceLocalIrSymbol(symbol, idSig) - if (idSig.isPubliclyVisible) { - deserializedSymbols[idSig]?.let { - require(it == symbol) { "Two different symbols for the same signature ${idSig.render()}" } - } - // Sometimes the linker would want to create a new symbol, so save actual symbol here - // and use it in [contains] and [tryDeserializeSymbol]. - deserializedSymbols[idSig] = symbol - } - } - - override fun contains(idSig: IdSignature): Boolean = - super.contains(idSig) || deserializedSymbols.containsKey(idSig) || - cacheDeserializationStrategy != CacheDeserializationStrategy.WholeModule - && idSig.isPubliclyVisible && descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null - - override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { - super.tryDeserializeIrSymbol(idSig, symbolKind)?.let { return it } - - deserializedSymbols[idSig]?.let { return it } - - val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: return null - - descriptorSignatures[descriptor] = idSig - - return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol - } - - private val inlineFunctionReferences by lazy { - val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 - cache.serializedInlineFunctionBodies.associateBy { - it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature) - } - } - - private val deserializedInlineFunctions = mutableMapOf() - - fun deserializeInlineFunction(function: IrFunction): DeserializedInlineFunction { - deserializedInlineFunctions[function]?.let { return DeserializedInlineFunction(firstAccess = false, it) } - val result = deserializeInlineFunctionInternal(function) - deserializedInlineFunctions[function] = result - return DeserializedInlineFunction(firstAccess = true, result) - } - - private fun deserializeInlineFunctionInternal(function: IrFunction): InlineFunctionOriginInfo { - val packageFragment = function.getPackageFragment() - if (function.parents.any { (it as? IrFunction)?.isInline == true }) { - // Already deserialized by the top-most inline function. - return InlineFunctionOriginInfo( - function, - packageFragment as? IrFile - ?: inlineFunctionFiles[packageFragment as IrExternalPackageFragment] - ?: error("${function.render()} should've been deserialized along with its parent"), - function.startOffset, function.endOffset - ) - } - - val signature = function.symbol.signature - ?: descriptorSignatures[function.descriptor] - ?: error("No signature for ${function.render()}") - val inlineFunctionReference = inlineFunctionReferences[signature] - ?: error("No inline function reference for ${function.render()}, sig = ${signature.render()}") - val fileDeserializationState = inlineFunctionReference.file.deserializationState - val declarationDeserializer = fileDeserializationState.declarationDeserializer - - if (packageFragment is IrExternalPackageFragment) { - val symbolDeserializer = declarationDeserializer.symbolDeserializer - - inlineFunctionFiles[packageFragment]?.let { - require(it == fileDeserializationState.file) { - "Different files ${it.fileEntry.name} and ${fileDeserializationState.file.fileEntry.name} have the same $packageFragment" - } - } - inlineFunctionFiles[packageFragment] = fileDeserializationState.file - - val outerClasses = (function.parent as? IrClass)?.getOuterClasses(takeOnlyInner = true) ?: emptyList() - require((outerClasses.getOrNull(0)?.firstNonClassParent ?: function.parent) is IrPackageFragment) { - "Local inline functions are not supported: ${function.render()}" - } - - var endToEndTypeParameterIndex = 0 - outerClasses.forEach { outerClass -> - outerClass.typeParameters.forEach { parameter -> - val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++] - referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) - } - } - function.typeParameters.forEach { parameter -> - val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++] - referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) - } - function.valueParameters.forEachIndexed { index, parameter -> - val sigIndex = inlineFunctionReference.valueParameterSigs[index] - referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) - } - function.extensionReceiverParameter?.let { parameter -> - val sigIndex = inlineFunctionReference.extensionReceiverSig - require(sigIndex != INVALID_INDEX) { "Expected a valid sig reference to the extension receiver for ${function.render()}" } - referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) - } - function.dispatchReceiverParameter?.let { parameter -> - val sigIndex = inlineFunctionReference.dispatchReceiverSig - require(sigIndex != INVALID_INDEX) { "Expected a valid sig reference to the dispatch receiver for ${function.render()}" } - referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) - } - for (index in 0 until outerClasses.size - 1) { - val sigIndex = inlineFunctionReference.outerReceiverSigs[index] - referenceIrSymbol(symbolDeserializer, sigIndex, outerClasses[index].thisReceiver!!.symbol) - } - } - - with(declarationDeserializer) { - function.withDeserializeBodies { - body = (deserializeStatementBody(inlineFunctionReference.body) as IrBody) - valueParameters.forEachIndexed { index, parameter -> - val defaultValueIndex = inlineFunctionReference.defaultValues[index] - if (defaultValueIndex != INVALID_INDEX) - parameter.defaultValue = deserializeExpressionBody(defaultValueIndex) - } - } - } - if (packageFragment is IrFile) - linker.deserializeAllReachableTopLevels() - - linker.partialLinkageSupport.exploreClassifiers(linker.fakeOverrideBuilder) - linker.partialLinkageSupport.exploreClassifiersInInlineLazyIrFunction(function) - - linker.fakeOverrideBuilder.provideFakeOverrides() - - linker.partialLinkageSupport.generateStubsAndPatchUsages(linker.symbolTable, function) - - linker.checkNoUnboundSymbols( - linker.symbolTable, - "after deserializing lazy-IR function ${function.name.asString()} in inline functions lowering" - ) - - return InlineFunctionOriginInfo(function, fileDeserializationState.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset) - } - - private val classesFields by lazy { - val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 - cache.serializedClassFields.associateBy { - it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.classSignature) - } - } - - private val lock = Any() - - fun deserializeClassFields(irClass: IrClass, outerThisFieldInfo: ClassLayoutBuilder.FieldInfo?): List = synchronized(lock) { - val signature = irClass.symbol.signature - ?: error("No signature for ${irClass.render()}") - val serializedClassFields = classesFields[signature] - ?: error("No class fields for ${irClass.render()}, sig = ${signature.render()}") - val fileDeserializationState = serializedClassFields.file.deserializationState - val declarationDeserializer = fileDeserializationState.declarationDeserializer - val symbolDeserializer = declarationDeserializer.symbolDeserializer - - if (irClass.getPackageFragment() is IrExternalPackageFragment) { - val outerClasses = irClass.getOuterClasses(takeOnlyInner = true) - require(outerClasses.first().firstNonClassParent is IrExternalPackageFragment) { - "Local classes are not supported: ${irClass.render()}" - } - - var endToEndTypeParameterIndex = 0 - outerClasses.forEach { outerClass -> - outerClass.typeParameters.forEach { parameter -> - val sigIndex = serializedClassFields.typeParameterSigs[endToEndTypeParameterIndex++] - referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) - } - } - require(endToEndTypeParameterIndex == serializedClassFields.typeParameterSigs.size) { - "Not all type parameters have been referenced" - } - } - - fun getByClassId(classId: ClassId): IrClassSymbol { - val classIdSig = getPublicSignature(classId.packageFqName, classId.relativeClassName.asString()) - return symbolDeserializer.deserializePublicSymbol(classIdSig, BinarySymbolData.SymbolKind.CLASS_SYMBOL) as IrClassSymbol - } - - return serializedClassFields.fields.mapIndexed { index, field -> - val builtIns = linker.builtIns - if (index == serializedClassFields.outerThisIndex) { - require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" } - require(outerThisFieldInfo != null) { "For an inner class ${irClass.render()} there should be field" } - outerThisFieldInfo.also { - require(it.alignment == field.alignment) { "Mismatched align information for outer this"} - } - } else { - val name = fileDeserializationState.fileReader.string(field.name) - val type = when { - field.type != INVALID_INDEX -> declarationDeserializer.deserializeIrType(field.type) - field.binaryType == INVALID_INDEX -> builtIns.anyNType - else -> when (PrimitiveBinaryType.values().getOrNull(field.binaryType)) { - PrimitiveBinaryType.BOOLEAN -> builtIns.booleanType - PrimitiveBinaryType.BYTE -> builtIns.byteType - PrimitiveBinaryType.SHORT -> builtIns.shortType - PrimitiveBinaryType.INT -> builtIns.intType - PrimitiveBinaryType.LONG -> builtIns.longType - PrimitiveBinaryType.FLOAT -> builtIns.floatType - PrimitiveBinaryType.DOUBLE -> builtIns.doubleType - PrimitiveBinaryType.POINTER -> getByClassId(KonanPrimitiveType.NON_NULL_NATIVE_PTR.classId).defaultType - PrimitiveBinaryType.VECTOR128 -> getByClassId(KonanPrimitiveType.VECTOR128.classId).defaultType - else -> error("Bad binary type of field $name of ${irClass.render()}") - } - } - ClassLayoutBuilder.FieldInfo( - name, type, - isConst = (field.flags and SerializedClassFieldInfo.FLAG_IS_CONST) != 0, - irFieldSymbol = IrFieldSymbolImpl(), - alignment = field.alignment, - ) - } - } - } - - private fun IrClass.getOuterClasses(takeOnlyInner: Boolean): List { - var outerClass = this - val outerClasses = mutableListOf(outerClass) - while (outerClass.isInner || !takeOnlyInner) { - outerClass = outerClass.parent as? IrClass ?: break - outerClasses.add(outerClass) - } - outerClasses.reverse() - return outerClasses - } - - val eagerInitializedFiles by lazy { - val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 - cache.serializedEagerInitializedFiles - .map { it.file.deserializationState.file } - .distinct() - } - - val sortedFileIds by lazy { - fileDeserializationStates - .sortedBy { it.file.fileEntry.name } - .map { CacheSupport.cacheFileId(it.file.packageFqName.asString(), it.file.fileEntry.name) } - } - } - private inner class KonanInteropModuleDeserializer( moduleDescriptor: ModuleDescriptor, override val klib: KotlinLibrary, diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanPartialModuleDeserializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanPartialModuleDeserializer.kt new file mode 100644 index 00000000000..718e9ee4a04 --- /dev/null +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanPartialModuleDeserializer.kt @@ -0,0 +1,528 @@ +/* + * 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.konan.serialization + +import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols +import org.jetbrains.kotlin.backend.common.lower.parents +import org.jetbrains.kotlin.backend.common.serialization.* +import org.jetbrains.kotlin.backend.common.serialization.encodings.BinaryNameAndType +import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData +import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.InlineFunctionOriginInfo +import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrBody +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl +import org.jetbrains.kotlin.ir.types.classifierOrNull +import org.jetbrains.kotlin.ir.types.defaultType +import org.jetbrains.kotlin.ir.types.getPublicSignature +import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.ir.util.getPackageFragment +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.library.KotlinAbiVersion +import org.jetbrains.kotlin.library.KotlinLibrary +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration +import org.jetbrains.kotlin.backend.common.serialization.proto.IrField as ProtoField + +@OptIn(ObsoleteDescriptorBasedAPI::class) +internal class KonanPartialModuleDeserializer( + konanIrLinker: KonanIrLinker, + moduleDescriptor: ModuleDescriptor, + override val klib: KotlinLibrary, + private val stubGenerator: DeclarationStubGenerator, + private val cachedLibraries: CachedLibraries, + private val inlineFunctionFiles: MutableMap, + strategyResolver: (String) -> DeserializationStrategy, + private val cacheDeserializationStrategy: CacheDeserializationStrategy, + containsErrorCode: Boolean = false +) : BasicIrModuleDeserializer(konanIrLinker, moduleDescriptor, klib, + { fileName -> + if (cacheDeserializationStrategy.contains(fileName)) + strategyResolver(fileName) + else DeserializationStrategy.ON_DEMAND + }, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT, containsErrorCode +) { + private val descriptorSignatures = mutableMapOf() + + val files by lazy { fileDeserializationStates.map { it.file } } + + private val idSignatureToFile by lazy { + buildMap { + fileDeserializationStates.forEach { fileDeserializationState -> + fileDeserializationState.fileDeserializer.reversedSignatureIndex.keys.forEach { idSig -> + put(idSig, fileDeserializationState.file) + } + } + } + } + + private val fileReferenceToFileDeserializationState by lazy { + fileDeserializationStates.associateBy { SerializedFileReference(it.file.packageFqName.asString(), it.file.path) } + } + + private val SerializedFileReference.deserializationState + get() = fileReferenceToFileDeserializationState[this] ?: error("Unknown file $this") + + private tailrec fun IdSignature.fileSignature(): IdSignature.FileSignature? = when (this) { + is IdSignature.FileSignature -> this + is IdSignature.CompositeSignature -> this.container.fileSignature() + else -> null + } + + private val IrClass.firstNonClassParent: IrDeclarationParent + get() { + var parent = parent + while (parent is IrClass) parent = parent.parent + return parent + } + + fun getFileNameOf(declaration: IrDeclaration): String { + fun IrDeclaration.getSignature() = symbol.signature ?: descriptorSignatures[descriptor] + + val idSig = declaration.getSignature() + ?: (declaration.parent as? IrDeclaration)?.getSignature() + ?: ((declaration as? IrAttributeContainer)?.attributeOwnerId as? IrDeclaration)?.getSignature() + ?: error("Can't find signature of ${declaration.render()}") + val topLevelIdSig = idSig.topLevelSignature() + return topLevelIdSig.fileSignature()?.fileName + ?: idSignatureToFile[topLevelIdSig]?.path + ?: error("No file for $idSig") + } + + fun getKlibFileIndexOf(irFile: IrFile) = fileDeserializationStates.first { it.file == irFile }.fileIndex + + fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference { + val signature = irFunction.symbol.signature + ?: error("No signature for ${irFunction.render()}") + val topLevelSignature = signature.topLevelSignature() + val fileDeserializationState = moduleReversedFileIndex[topLevelSignature] + ?: error("No file deserializer for ${topLevelSignature.render()}") + val declarationIndex = fileDeserializationState.fileDeserializer.reversedSignatureIndex[topLevelSignature] + ?: error("No declaration for ${topLevelSignature.render()}") + val fileReader = fileDeserializationState.fileReader + val symbolDeserializer = fileDeserializationState.fileDeserializer.symbolDeserializer + val protoDeclaration = fileReader.declaration(declarationIndex) + + val outerClasses = (irFunction.parent as? IrClass)?.getOuterClasses(takeOnlyInner = false) ?: emptyList() + require((outerClasses.getOrNull(0)?.parent ?: irFunction.parent) is IrFile) { + "Local inline functions are not supported: ${irFunction.render()}" + } + + val typeParameterSigs = mutableListOf() + val outerReceiverSigs = mutableListOf() + val protoFunction = if (outerClasses.isEmpty()) { + val irProperty = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner + if (irProperty == null) + protoDeclaration.irFunction + else protoDeclaration.irProperty.findAccessor(irProperty, irFunction) + } else { + val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner } + var protoClass = protoDeclaration.irClass + outerClasses.indices.forEach { classIndex -> + if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) { + (0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) { + BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId + } + } + if (classIndex < outerClasses.size - 1) { + if (classIndex >= firstNotInnerClassIndex) + outerReceiverSigs.add(BinarySymbolData.decode(protoClass.thisReceiver.base.symbol).signatureId) + protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer) + } + } + protoClass.findInlineFunction(irFunction, fileReader, symbolDeserializer) + } + + val functionSignature = BinarySymbolData.decode(protoFunction.base.base.symbol).signatureId + (0 until protoFunction.base.typeParameterCount).mapTo(typeParameterSigs) { + BinarySymbolData.decode(protoFunction.base.getTypeParameter(it).base.symbol).signatureId + } + val defaultValues = mutableListOf() + val valueParameterSigs = (0 until protoFunction.base.valueParameterCount).map { + val valueParameter = protoFunction.base.getValueParameter(it) + defaultValues.add(if (valueParameter.hasDefaultValue()) valueParameter.defaultValue else KonanIrLinker.INVALID_INDEX) + BinarySymbolData.decode(valueParameter.base.symbol).signatureId + } + val extensionReceiverSig = irFunction.extensionReceiverParameter?.let { + BinarySymbolData.decode(protoFunction.base.extensionReceiver.base.symbol).signatureId + } ?: KonanIrLinker.INVALID_INDEX + val dispatchReceiverSig = irFunction.dispatchReceiverParameter?.let { + BinarySymbolData.decode(protoFunction.base.dispatchReceiver.base.symbol).signatureId + } ?: KonanIrLinker.INVALID_INDEX + + return SerializedInlineFunctionReference( + SerializedFileReference(fileDeserializationState.file), + functionSignature, protoFunction.base.body, irFunction.startOffset, irFunction.endOffset, + extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs.toIntArray(), + valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray() + ) + } + + fun buildClassFields(irClass: IrClass, fields: List): SerializedClassFields { + val signature = irClass.symbol.signature + ?: error("No signature for ${irClass.render()}") + val topLevelSignature = signature.topLevelSignature() + val fileDeserializationState = moduleReversedFileIndex[topLevelSignature] + ?: error("No file deserializer for ${topLevelSignature.render()}") + val fileDeserializer = fileDeserializationState.fileDeserializer + val declarationIndex = fileDeserializer.reversedSignatureIndex[topLevelSignature] + ?: error("No declaration for ${topLevelSignature.render()}") + val fileReader = fileDeserializationState.fileReader + val symbolDeserializer = fileDeserializer.symbolDeserializer + val protoDeclaration = fileReader.declaration(declarationIndex) + + val outerClasses = irClass.getOuterClasses(takeOnlyInner = false) + require(outerClasses.first().parent is IrFile) { "Local classes are not supported: ${irClass.render()}" } + + val typeParameterSigs = mutableListOf() + var protoClass = protoDeclaration.irClass + val protoClasses = mutableListOf(protoClass) + val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner } + for (classIndex in outerClasses.indices) { + if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) { + (0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) { + BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId + } + } + if (classIndex < outerClasses.size - 1) { + protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer) + protoClasses += protoClass + } + } + + val protoFields = mutableListOf() + for (i in 0 until protoClass.declarationCount) { + val declaration = protoClass.getDeclaration(i) + if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_FIELD) + protoFields.add(declaration.irField) + else if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_PROPERTY) { + val protoProperty = declaration.irProperty + if (protoProperty.hasBackingField()) + protoFields.add(protoProperty.backingField) + } + } + val protoFieldsMap = mutableMapOf() + protoFields.forEach { + val nameAndType = BinaryNameAndType.decode(it.nameType) + val name = fileReader.string(nameAndType.nameIndex) + val prev = protoFieldsMap[name] + if (prev != null) + error("Class ${irClass.render()} has two fields with same name '$name'") + protoFieldsMap[name] = it + } + + val outerThisIndex = fields.indexOfFirst { it.irField?.origin == IrDeclarationOrigin.FIELD_FOR_OUTER_THIS } + val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures + return SerializedClassFields( + SerializedFileReference(fileDeserializationState.file), + BinarySymbolData.decode(protoClass.base.symbol).signatureId, + typeParameterSigs.toIntArray(), + outerThisIndex, + Array(fields.size) { + val field = fields[it] + val irField = field.irField ?: error("No IR for field ${field.name} of ${irClass.render()}") + if (it == outerThisIndex) { + require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" } + require(protoClasses.size > 1) { "An inner class must have at least one outer class" } + val outerProtoClass = protoClasses[protoClasses.size - 2] + val nameAndType = BinaryNameAndType.decode(outerProtoClass.thisReceiver.nameType) + + SerializedClassFieldInfo( + name = KonanIrLinker.INVALID_INDEX, + binaryType = KonanIrLinker.INVALID_INDEX, + nameAndType.typeIndex, + flags = 0, + field.alignment + ) + } else { + val protoField = protoFieldsMap[field.name] ?: error("No proto for ${irField.render()}") + val nameAndType = BinaryNameAndType.decode(protoField.nameType) + var flags = 0 + if (field.isConst) + flags = flags or SerializedClassFieldInfo.FLAG_IS_CONST + val classifier = irField.type.classifierOrNull + ?: error("Fields of type ${irField.type.render()} are not supported") + val primitiveBinaryType = irField.type.computePrimitiveBinaryTypeOrNull() + + SerializedClassFieldInfo( + nameAndType.nameIndex, + primitiveBinaryType?.ordinal ?: KonanIrLinker.INVALID_INDEX, + if (with(KonanManglerIr) { (classifier as? IrClassSymbol)?.owner?.isExported(compatibleMode) } == false) + KonanIrLinker.INVALID_INDEX + else nameAndType.typeIndex, + flags, + field.alignment + ) + } + }) + } + + fun buildEagerInitializedFile(irFile: IrFile) = + SerializedEagerInitializedFile(SerializedFileReference(irFile)) + + private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl( + moduleDescriptor, KonanManglerDesc, + DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY + ) + + private val deserializedSymbols = mutableMapOf() + + // Need to notify the deserializing machinery that some symbols have already been created by stub generator + // (like type parameters and receiver parameters) and there's no need to create new symbols for them. + private fun referenceIrSymbol(symbolDeserializer: IrSymbolDeserializer, sigIndex: Int, symbol: IrSymbol) { + val idSig = symbolDeserializer.deserializeIdSignature(sigIndex) + symbolDeserializer.referenceLocalIrSymbol(symbol, idSig) + if (idSig.isPubliclyVisible) { + deserializedSymbols[idSig]?.let { + require(it == symbol) { "Two different symbols for the same signature ${idSig.render()}" } + } + // Sometimes the linker would want to create a new symbol, so save actual symbol here + // and use it in [contains] and [tryDeserializeSymbol]. + deserializedSymbols[idSig] = symbol + } + } + + override fun contains(idSig: IdSignature): Boolean = + super.contains(idSig) || deserializedSymbols.containsKey(idSig) || + cacheDeserializationStrategy != CacheDeserializationStrategy.WholeModule + && idSig.isPubliclyVisible && descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null + + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { + super.tryDeserializeIrSymbol(idSig, symbolKind)?.let { return it } + + deserializedSymbols[idSig]?.let { return it } + + val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: return null + + descriptorSignatures[descriptor] = idSig + + return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol + } + + private val inlineFunctionReferences by lazy { + val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 + cache.serializedInlineFunctionBodies.associateBy { + it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature) + } + } + + private val deserializedInlineFunctions = mutableMapOf() + + fun deserializeInlineFunction(function: IrFunction): DeserializedInlineFunction { + deserializedInlineFunctions[function]?.let { return DeserializedInlineFunction(firstAccess = false, it) } + val result = deserializeInlineFunctionInternal(function) + deserializedInlineFunctions[function] = result + return DeserializedInlineFunction(firstAccess = true, result) + } + + private fun deserializeInlineFunctionInternal(function: IrFunction): InlineFunctionOriginInfo { + val packageFragment = function.getPackageFragment() + if (function.parents.any { (it as? IrFunction)?.isInline == true }) { + // Already deserialized by the top-most inline function. + return InlineFunctionOriginInfo( + function, + packageFragment as? IrFile + ?: inlineFunctionFiles[packageFragment as IrExternalPackageFragment] + ?: error("${function.render()} should've been deserialized along with its parent"), + function.startOffset, function.endOffset + ) + } + + val signature = function.symbol.signature + ?: descriptorSignatures[function.descriptor] + ?: error("No signature for ${function.render()}") + val inlineFunctionReference = inlineFunctionReferences[signature] + ?: error("No inline function reference for ${function.render()}, sig = ${signature.render()}") + val fileDeserializationState = inlineFunctionReference.file.deserializationState + val declarationDeserializer = fileDeserializationState.declarationDeserializer + + if (packageFragment is IrExternalPackageFragment) { + val symbolDeserializer = declarationDeserializer.symbolDeserializer + + inlineFunctionFiles[packageFragment]?.let { + require(it == fileDeserializationState.file) { + "Different files ${it.fileEntry.name} and ${fileDeserializationState.file.fileEntry.name} have the same $packageFragment" + } + } + inlineFunctionFiles[packageFragment] = fileDeserializationState.file + + val outerClasses = (function.parent as? IrClass)?.getOuterClasses(takeOnlyInner = true) ?: emptyList() + require((outerClasses.getOrNull(0)?.firstNonClassParent ?: function.parent) is IrPackageFragment) { + "Local inline functions are not supported: ${function.render()}" + } + + var endToEndTypeParameterIndex = 0 + outerClasses.forEach { outerClass -> + outerClass.typeParameters.forEach { parameter -> + val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++] + referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) + } + } + function.typeParameters.forEach { parameter -> + val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++] + referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) + } + function.valueParameters.forEachIndexed { index, parameter -> + val sigIndex = inlineFunctionReference.valueParameterSigs[index] + referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) + } + function.extensionReceiverParameter?.let { parameter -> + val sigIndex = inlineFunctionReference.extensionReceiverSig + require(sigIndex != KonanIrLinker.INVALID_INDEX) { "Expected a valid sig reference to the extension receiver for ${function.render()}" } + referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) + } + function.dispatchReceiverParameter?.let { parameter -> + val sigIndex = inlineFunctionReference.dispatchReceiverSig + require(sigIndex != KonanIrLinker.INVALID_INDEX) { "Expected a valid sig reference to the dispatch receiver for ${function.render()}" } + referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) + } + for (index in 0 until outerClasses.size - 1) { + val sigIndex = inlineFunctionReference.outerReceiverSigs[index] + referenceIrSymbol(symbolDeserializer, sigIndex, outerClasses[index].thisReceiver!!.symbol) + } + } + + with(declarationDeserializer) { + function.withDeserializeBodies { + body = (deserializeStatementBody(inlineFunctionReference.body) as IrBody) + valueParameters.forEachIndexed { index, parameter -> + val defaultValueIndex = inlineFunctionReference.defaultValues[index] + if (defaultValueIndex != KonanIrLinker.INVALID_INDEX) + parameter.defaultValue = deserializeExpressionBody(defaultValueIndex) + } + } + } + if (packageFragment is IrFile) + linker.deserializeAllReachableTopLevels() + + linker.partialLinkageSupport.exploreClassifiers(linker.fakeOverrideBuilder) + linker.partialLinkageSupport.exploreClassifiersInInlineLazyIrFunction(function) + + linker.fakeOverrideBuilder.provideFakeOverrides() + + linker.partialLinkageSupport.generateStubsAndPatchUsages(linker.symbolTable, function) + + linker.checkNoUnboundSymbols( + linker.symbolTable, + "after deserializing lazy-IR function ${function.name.asString()} in inline functions lowering" + ) + + return InlineFunctionOriginInfo( + function, + fileDeserializationState.file, + inlineFunctionReference.startOffset, + inlineFunctionReference.endOffset + ) + } + + private val classesFields by lazy { + val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 + cache.serializedClassFields.associateBy { + it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.classSignature) + } + } + + private val lock = Any() + + fun deserializeClassFields(irClass: IrClass, outerThisFieldInfo: ClassLayoutBuilder.FieldInfo?): List = synchronized(lock) { + val signature = irClass.symbol.signature + ?: error("No signature for ${irClass.render()}") + val serializedClassFields = classesFields[signature] + ?: error("No class fields for ${irClass.render()}, sig = ${signature.render()}") + val fileDeserializationState = serializedClassFields.file.deserializationState + val declarationDeserializer = fileDeserializationState.declarationDeserializer + val symbolDeserializer = declarationDeserializer.symbolDeserializer + + if (irClass.getPackageFragment() is IrExternalPackageFragment) { + val outerClasses = irClass.getOuterClasses(takeOnlyInner = true) + require(outerClasses.first().firstNonClassParent is IrExternalPackageFragment) { + "Local classes are not supported: ${irClass.render()}" + } + + var endToEndTypeParameterIndex = 0 + outerClasses.forEach { outerClass -> + outerClass.typeParameters.forEach { parameter -> + val sigIndex = serializedClassFields.typeParameterSigs[endToEndTypeParameterIndex++] + referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol) + } + } + require(endToEndTypeParameterIndex == serializedClassFields.typeParameterSigs.size) { + "Not all type parameters have been referenced" + } + } + + fun getByClassId(classId: ClassId): IrClassSymbol { + val classIdSig = getPublicSignature(classId.packageFqName, classId.relativeClassName.asString()) + return symbolDeserializer.deserializePublicSymbol(classIdSig, BinarySymbolData.SymbolKind.CLASS_SYMBOL) as IrClassSymbol + } + + return serializedClassFields.fields.mapIndexed { index, field -> + val builtIns = linker.builtIns + if (index == serializedClassFields.outerThisIndex) { + require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" } + require(outerThisFieldInfo != null) { "For an inner class ${irClass.render()} there should be field" } + outerThisFieldInfo.also { + require(it.alignment == field.alignment) { "Mismatched align information for outer this"} + } + } else { + val name = fileDeserializationState.fileReader.string(field.name) + val type = when { + field.type != KonanIrLinker.INVALID_INDEX -> declarationDeserializer.deserializeIrType(field.type) + field.binaryType == KonanIrLinker.INVALID_INDEX -> builtIns.anyNType + else -> when (PrimitiveBinaryType.values().getOrNull(field.binaryType)) { + PrimitiveBinaryType.BOOLEAN -> builtIns.booleanType + PrimitiveBinaryType.BYTE -> builtIns.byteType + PrimitiveBinaryType.SHORT -> builtIns.shortType + PrimitiveBinaryType.INT -> builtIns.intType + PrimitiveBinaryType.LONG -> builtIns.longType + PrimitiveBinaryType.FLOAT -> builtIns.floatType + PrimitiveBinaryType.DOUBLE -> builtIns.doubleType + PrimitiveBinaryType.POINTER -> getByClassId(KonanPrimitiveType.NON_NULL_NATIVE_PTR.classId).defaultType + PrimitiveBinaryType.VECTOR128 -> getByClassId(KonanPrimitiveType.VECTOR128.classId).defaultType + else -> error("Bad binary type of field $name of ${irClass.render()}") + } + } + ClassLayoutBuilder.FieldInfo( + name, type, + isConst = (field.flags and SerializedClassFieldInfo.FLAG_IS_CONST) != 0, + irFieldSymbol = IrFieldSymbolImpl(), + alignment = field.alignment, + ) + } + } + } + + private fun IrClass.getOuterClasses(takeOnlyInner: Boolean): List { + var outerClass = this + val outerClasses = mutableListOf(outerClass) + while (outerClass.isInner || !takeOnlyInner) { + outerClass = outerClass.parent as? IrClass ?: break + outerClasses.add(outerClass) + } + outerClasses.reverse() + return outerClasses + } + + val eagerInitializedFiles by lazy { + val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 + cache.serializedEagerInitializedFiles + .map { it.file.deserializationState.file } + .distinct() + } + + val sortedFileIds by lazy { + fileDeserializationStates + .sortedBy { it.file.fileEntry.name } + .map { CacheSupport.cacheFileId(it.file.packageFqName.asString(), it.file.fileEntry.name) } + } +} \ No newline at end of file