diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CacheSupport.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CacheSupport.kt index 4851f17c1cc..7087a09f007 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CacheSupport.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CacheSupport.kt @@ -13,6 +13,20 @@ import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult +sealed class CacheDeserializationStrategy { + abstract fun contains(filePath: String): Boolean + + object Nothing : CacheDeserializationStrategy() { + override fun contains(filePath: String) = false + } + + object WholeModule : CacheDeserializationStrategy() { + override fun contains(filePath: String) = true + } +} + +class PartialCacheInfo(val klib: KotlinLibrary, val strategy: CacheDeserializationStrategy) + class CacheSupport( private val configuration: CompilerConfiguration, resolvedLibraries: KotlinLibraryResolveResult, @@ -90,6 +104,10 @@ class CacheSupport( } } + internal val libraryToCache = librariesToCache.singleOrNull()?.let { + PartialCacheInfo(it, CacheDeserializationStrategy.WholeModule) + } + internal val preLinkCaches: Boolean = configuration.get(KonanConfigKeys.PRE_LINK_CACHES, false) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 7515bae0897..898b31c80e6 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -220,7 +220,6 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration konanKlibDir = File(distribution.klib) ) - val fullExportedNamePrefix: String get() = configuration.get(KonanConfigKeys.FULL_EXPORTED_NAME_PREFIX) ?: implicitModuleName @@ -398,6 +397,9 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration internal val librariesToCache: Set get() = cacheSupport.librariesToCache + internal val libraryToCache: PartialCacheInfo? + get() = cacheSupport.libraryToCache + val outputFiles = OutputFiles(configuration.get(KonanConfigKeys.OUTPUT) ?: cacheSupport.tryGetImplicitOutput(), target, produce) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt index 5263817ef1f..0a398db87f4 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt @@ -123,6 +123,7 @@ internal fun Context.psiToIr( exportedDependencies = exportedDependencies, cachedLibraries = config.cachedLibraries, lazyIrForCaches = config.lazyIrForCaches, + libraryBeingCached = config.libraryToCache, unlinkedDeclarationsSupport = unlinkedDeclarationsSupport, userVisibleIrModulesSupport = config.userVisibleIrModulesSupport ).also { linker -> diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index 9a3b38f3d05..8cf29ee5d51 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -129,7 +129,7 @@ internal val psiToIrPhase = konanUnitPhase( internal val buildAdditionalCacheInfoPhase = konanUnitPhase( op = { irModules.values.single().let { module -> - val moduleDeserializer = irLinker.nonCachedLibraryModuleDeserializers[module.descriptor] + val moduleDeserializer = irLinker.moduleDeserializers[module.descriptor] if (moduleDeserializer == null) { require(module.descriptor.isFromInteropLibrary()) { "No module deserializer for ${module.descriptor}" } } else { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt index bd10339a40e..d8002cbcfe4 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt @@ -473,7 +473,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) { val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration if (moduleDescriptor.isFromInteropLibrary()) return emptyList() - val moduleDeserializer = context.irLinker.cachedLibraryModuleDeserializers[moduleDescriptor] + val moduleDeserializer = context.irLinker.moduleDeserializers[moduleDescriptor] ?: error("No module deserializer for ${irClass.render()}") return moduleDeserializer.deserializeClassFields(irClass, outerThisField) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt index 036c62bd315..9c253d3243f 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt @@ -38,7 +38,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def } else { // The function is from Lazy IR, get its body from the IR linker. val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration - val moduleDeserializer = context.irLinker.cachedLibraryModuleDeserializers[moduleDescriptor] + val moduleDeserializer = context.irLinker.moduleDeserializers[moduleDescriptor] ?: error("No module deserializer for ${function.render()}") context.specialDeclarationsFactory.loweredInlineFunctions[function] = moduleDeserializer.deserializeInlineFunction(function) function 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 1155c49404e..b6492bf1d5e 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 @@ -42,6 +42,8 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl 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.IrPropertySymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase import org.jetbrains.kotlin.ir.types.* @@ -322,6 +324,7 @@ internal class KonanIrLinker( exportedDependencies: List, private val cachedLibraries: CachedLibraries, private val lazyIrForCaches: Boolean, + private val libraryBeingCached: PartialCacheInfo?, override val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport, override val userVisibleIrModulesSupport: UserVisibleIrModulesSupport ) : KotlinIrLinker(currentModule, messageLogger, builtIns, symbolTable, exportedDependencies) { @@ -341,8 +344,7 @@ internal class KonanIrLinker( override val fakeOverrideBuilder: FakeOverrideBuilder = FakeOverrideBuilder(this, symbolTable, KonanManglerIr, IrTypeSystemContextImpl(builtIns), friendModules, KonanFakeOverrideClassFilter) - val nonCachedLibraryModuleDeserializers = mutableMapOf() - val cachedLibraryModuleDeserializers = mutableMapOf() + val moduleDeserializers = mutableMapOf() override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary?, strategyResolver: (String) -> DeserializationStrategy) = when { @@ -355,14 +357,14 @@ internal class KonanIrLinker( klib.isInteropLibrary() -> { KonanInteropModuleDeserializer(moduleDescriptor, klib, cachedLibraries.isLibraryCached(klib)) } - lazyIrForCaches && cachedLibraries.isLibraryCached(klib) -> { - KonanCachedLibraryModuleDeserializer(moduleDescriptor, klib).also { - cachedLibraryModuleDeserializers[moduleDescriptor] = it - } - } else -> { - KonanModuleDeserializer(moduleDescriptor, klib, strategyResolver).also { - nonCachedLibraryModuleDeserializers[moduleDescriptor] = it + val deserializationStrategy = when { + klib == libraryBeingCached?.klib -> libraryBeingCached.strategy + lazyIrForCaches && cachedLibraries.isLibraryCached(klib) -> CacheDeserializationStrategy.Nothing + else -> CacheDeserializationStrategy.WholeModule + } + KonanPartialModuleDeserializer(moduleDescriptor, klib, strategyResolver, deserializationStrategy).also { + moduleDeserializers[moduleDescriptor] = it } } } @@ -401,12 +403,19 @@ internal class KonanIrLinker( private val InvalidIndex = -1 - inner class KonanModuleDeserializer( + inner class KonanPartialModuleDeserializer( moduleDescriptor: ModuleDescriptor, - klib: KotlinLibrary, - strategyResolver: (String) -> DeserializationStrategy - ) : BasicIrModuleDeserializer(this@KonanIrLinker, moduleDescriptor, klib, strategyResolver, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) { - override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList()) + override val klib: KotlinLibrary, + strategyResolver: (String) -> DeserializationStrategy, + private val cacheDeserializationStrategy: CacheDeserializationStrategy, + containsErrorCode: Boolean = false + ) : BasicIrModuleDeserializer(this, moduleDescriptor, klib, + { fileName -> + if (cacheDeserializationStrategy.contains(fileName)) + strategyResolver(fileName) + else DeserializationStrategy.ON_DEMAND + }, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT, containsErrorCode) { + override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns) fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference { val signature = irFunction.symbol.signature @@ -562,76 +571,6 @@ internal class KonanIrLinker( } }) } - } - - private inner class KonanInteropModuleDeserializer( - moduleDescriptor: ModuleDescriptor, - override val klib: KotlinLibrary, - private val isLibraryCached: Boolean - ) : IrModuleDeserializer(moduleDescriptor, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) { - init { - require(klib.isInteropLibrary()) - } - - private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl( - moduleDescriptor, KonanManglerDesc, - DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY - ) - - private fun IdSignature.isInteropSignature() = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() - - override fun contains(idSig: IdSignature): Boolean { - if (idSig.isPubliclyVisible) { - if (idSig.isInteropSignature()) { - // TODO: add descriptor cache?? - return descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null - } - } - - return false - } - - private fun DeclarationDescriptor.isCEnumsOrCStruct(): Boolean = cenumsProvider.isCEnumOrCStruct(this) - - private val fileMap = mutableMapOf() - - private fun getIrFile(packageFragment: PackageFragmentDescriptor): IrFile = fileMap.getOrPut(packageFragment) { - IrFileImpl(NaiveSourceBasedFileEntryImpl(IrProviderForCEnumAndCStructStubs.cTypeDefinitionsFileName), packageFragment).also { - moduleFragment.files.add(it) - } - } - - private fun resolveCEnumsOrStruct(descriptor: DeclarationDescriptor, idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { - val file = getIrFile(descriptor.findPackage()) - return cenumsProvider.getDeclaration(descriptor, idSig, file, symbolKind).symbol - } - - override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { - val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: return null - // If library is cached we don't need to create an IrClass for struct or enum. - if (!isLibraryCached && descriptor.isCEnumsOrCStruct()) return resolveCEnumsOrStruct(descriptor, idSig, symbolKind) - - val symbolOwner = stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner - - return symbolOwner.symbol - } - - override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig") - - override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns) - override val moduleDependencies: Collection = listOfNotNull(forwardDeclarationDeserializer) - - override val kind get() = IrModuleDeserializerKind.DESERIALIZED - } - - inner class KonanCachedLibraryModuleDeserializer( - moduleDescriptor: ModuleDescriptor, - override val klib: KotlinLibrary - ) : BasicIrModuleDeserializer(this@KonanIrLinker, moduleDescriptor, klib, - { _ -> DeserializationStrategy.ON_DEMAND }, - klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT - ) { - override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList()) private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl( moduleDescriptor, KonanManglerDesc, @@ -655,14 +594,22 @@ internal class KonanIrLinker( } } - override fun contains(idSig: IdSignature) = - deserializedSymbols.containsKey(idSig) || - idSig.isPubliclyVisible && descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null + override fun contains(idSig: IdSignature): Boolean = + super.contains(idSig) || deserializedSymbols.containsKey(idSig) || + cacheDeserializationStrategy != CacheDeserializationStrategy.WholeModule + && idSig.isPubliclyVisible && descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null + + val descriptorSignatures = mutableMapOf() 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 } @@ -687,7 +634,7 @@ internal class KonanIrLinker( ) } - val signature = function.symbol.signature + 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()}") @@ -819,6 +766,66 @@ internal class KonanIrLinker( } } + private inner class KonanInteropModuleDeserializer( + moduleDescriptor: ModuleDescriptor, + override val klib: KotlinLibrary, + private val isLibraryCached: Boolean + ) : IrModuleDeserializer(moduleDescriptor, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) { + init { + require(klib.isInteropLibrary()) + } + + private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl( + moduleDescriptor, KonanManglerDesc, + DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY + ) + + private fun IdSignature.isInteropSignature() = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() + + override fun contains(idSig: IdSignature): Boolean { + if (idSig.isPubliclyVisible) { + if (idSig.isInteropSignature()) { + // TODO: add descriptor cache?? + return descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null + } + } + + return false + } + + private fun DeclarationDescriptor.isCEnumsOrCStruct(): Boolean = cenumsProvider.isCEnumOrCStruct(this) + + private val fileMap = mutableMapOf() + + private fun getIrFile(packageFragment: PackageFragmentDescriptor): IrFile = fileMap.getOrPut(packageFragment) { + IrFileImpl(NaiveSourceBasedFileEntryImpl(IrProviderForCEnumAndCStructStubs.cTypeDefinitionsFileName), packageFragment).also { + moduleFragment.files.add(it) + } + } + + private fun resolveCEnumsOrStruct(descriptor: DeclarationDescriptor, idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + val file = getIrFile(descriptor.findPackage()) + return cenumsProvider.getDeclaration(descriptor, idSig, file, symbolKind).symbol + } + + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { + val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: return null + // If library is cached we don't need to create an IrClass for struct or enum. + if (!isLibraryCached && descriptor.isCEnumsOrCStruct()) return resolveCEnumsOrStruct(descriptor, idSig, symbolKind) + + val symbolOwner = stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner + + return symbolOwner.symbol + } + + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig") + + override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns) + override val moduleDependencies: Collection = listOfNotNull(forwardDeclarationDeserializer) + + override val kind get() = IrModuleDeserializerKind.DESERIALIZED + } + private inner class KonanForwardDeclarationModuleDeserializer(moduleDescriptor: ModuleDescriptor) : IrModuleDeserializer(moduleDescriptor, KotlinAbiVersion.CURRENT) { init { require(moduleDescriptor.isForwardDeclarationModule)