From 973210076455ad38ab9f7666f22825c1c9fe3965 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Fri, 9 Dec 2022 23:15:18 +0200 Subject: [PATCH] [K/N][IR][codegen] Introduced DependenciesTracker --- .../library/metadata/KlibModuleOrigin.kt | 12 - .../kotlin/backend/konan/CompilerOutput.kt | 4 +- .../backend/konan/DependenciesTracker.kt | 269 ++++++++++++++++++ .../jetbrains/kotlin/backend/konan/Linker.kt | 13 +- .../backend/konan/NativeGenerationState.kt | 28 +- .../kotlin/backend/konan/ToplevelPhases.kt | 1 - .../konan/driver/phases/TopLevelPhases.kt | 7 +- .../backend/konan/llvm/CodeGenerator.kt | 16 +- .../kotlin/backend/konan/llvm/ContextUtils.kt | 213 +------------- .../kotlin/backend/konan/llvm/Imports.kt | 12 - .../kotlin/backend/konan/llvm/IrToBitcode.kt | 13 +- .../llvm/KotlinObjCClassInfoGenerator.kt | 10 +- .../backend/konan/llvm/KotlinStaticData.kt | 3 +- .../konan/llvm/LlvmFunctionPrototype.kt | 17 +- .../kotlin/backend/konan/llvm/LlvmUtils.kt | 10 +- .../objcexport/ObjCExportCodeGenerator.kt | 35 ++- .../backend/konan/lower/CachesAbiLowering.kt | 8 +- .../backend/konan/lower/InteropLowering.kt | 4 +- 18 files changed, 343 insertions(+), 332 deletions(-) create mode 100644 kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DependenciesTracker.kt diff --git a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibModuleOrigin.kt b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibModuleOrigin.kt index 77757e64c8c..fd36974aeed 100644 --- a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibModuleOrigin.kt +++ b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibModuleOrigin.kt @@ -35,15 +35,3 @@ val ModuleDescriptor.klibModuleOrigin get() = this.getCapability(KlibModuleOrigi val ModuleDescriptor.kotlinLibrary get() = (this.klibModuleOrigin as DeserializedKlibModuleOrigin) .library - -sealed class CompiledKlibFileOrigin { - object CurrentFile : CompiledKlibFileOrigin() // No dependency should be added. - - object StdlibRuntime : CompiledKlibFileOrigin() - - object StdlibKFunctionImpl : CompiledKlibFileOrigin() - - class EntireModule(val library: KotlinLibrary) : CompiledKlibFileOrigin() - - class CertainFile(val library: KotlinLibrary, val fqName: String, val filePath: String) : CompiledKlibFileOrigin() -} \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt index a02f87ce7c4..df68fc1edae 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CompilerOutput.kt @@ -119,7 +119,7 @@ private data class LlvmModules( private fun collectLlvmModules(generationState: NativeGenerationState, generatedBitcodeFiles: List): LlvmModules { val config = generationState.config - val (bitcodePartOfStdlib, bitcodeLibraries) = generationState.llvm.bitcodeToLink + val (bitcodePartOfStdlib, bitcodeLibraries) = generationState.dependenciesTracker.bitcodeToLink .partition { it.isStdlib && generationState.producedLlvmModuleContainsStdlib } .toList() .map { libraries -> @@ -231,7 +231,7 @@ private fun embedAppleLinkerOptionsToBitcode(llvm: Llvm, config: KonanConfig) { } val optionsToEmbed = findEmbeddableOptions(config.platform.configurables.linkerKonanFlags) + - llvm.allNativeDependencies.flatMap { findEmbeddableOptions(it.linkerOpts) } + llvm.dependenciesTracker.allNativeDependencies.flatMap { findEmbeddableOptions(it.linkerOpts) } embedLlvmLinkOptions(llvm.llvmContext, llvm.module, optionsToEmbed) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DependenciesTracker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DependenciesTracker.kt new file mode 100644 index 00000000000..93bfd2dc11b --- /dev/null +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DependenciesTracker.kt @@ -0,0 +1,269 @@ +/* + * Copyright 2010-2022 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 + +import org.jetbrains.kotlin.backend.common.atMostOne +import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary +import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary +import org.jetbrains.kotlin.backend.konan.llvm.FunctionOrigin +import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin +import org.jetbrains.kotlin.backend.konan.llvm.standardLlvmSymbolsOrigin +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.util.getPackageFragment +import org.jetbrains.kotlin.konan.library.KonanLibrary +import org.jetbrains.kotlin.library.KotlinLibrary +import org.jetbrains.kotlin.library.uniqueName +import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin +import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin +import org.jetbrains.kotlin.library.metadata.resolver.TopologicalLibraryOrder +import org.jetbrains.kotlin.name.FqName + +private sealed class FileOrigin { + object CurrentFile : FileOrigin() // No dependency should be added. + + object StdlibRuntime : FileOrigin() + + object StdlibKFunctionImpl : FileOrigin() + + class EntireModule(val library: KotlinLibrary) : FileOrigin() + + class CertainFile(val library: KotlinLibrary, val fqName: String, val filePath: String) : FileOrigin() +} + +internal class DependenciesTracker(private val generationState: NativeGenerationState) { + data class LibraryFile(val library: KotlinLibrary, val fqName: String, val filePath: String) + + sealed class CachedBitcodeDependency(val library: KonanLibrary) { + class WholeModule(library: KonanLibrary) : CachedBitcodeDependency(library) + + class CertainFiles(library: KonanLibrary, val files: List) : CachedBitcodeDependency(library) + } + + private val config = generationState.config + private val context = generationState.context + + private val usedBitcode = mutableSetOf() + private val usedNativeDependencies = mutableSetOf() + private val usedBitcodeOfFile = mutableSetOf() + + private val allLibraries by lazy { context.librariesWithDependencies.toSet() } + + private fun findStdlibFile(fqName: FqName, fileName: String): LibraryFile { + val stdlib = (context.standardLlvmSymbolsOrigin as? DeserializedKlibModuleOrigin)?.library + ?: error("Can't find stdlib") + val stdlibDeserializer = context.irLinker.moduleDeserializers[context.stdlibModule] + ?: error("No deserializer for stdlib") + val file = stdlibDeserializer.files.atMostOne { it.fqName == fqName && it.name == fileName } + ?: error("Can't find $fqName:$fileName in stdlib") + return LibraryFile(stdlib, file.fqName.asString(), file.path) + } + + private val stdlibRuntime by lazy { findStdlibFile(KonanFqNames.internalPackageName, "Runtime.kt") } + private val stdlibKFunctionImpl by lazy { findStdlibFile(KonanFqNames.internalPackageName, "KFunctionImpl.kt") } + + private var sealed = false + + fun add(functionOrigin: FunctionOrigin, onlyBitcode: Boolean = false) = when (functionOrigin) { + FunctionOrigin.FromNativeRuntime -> addNativeRuntime(onlyBitcode) + is FunctionOrigin.OwnedBy -> add(functionOrigin.declaration, onlyBitcode) + } + + fun add(irFile: IrFile, onlyBitcode: Boolean = false): Unit = + add(computeFileOrigin(irFile) { irFile.path }, onlyBitcode) + + fun add(declaration: IrDeclaration, onlyBitcode: Boolean = false): Unit = + add(computeFileOrigin(declaration.getPackageFragment()) { + context.irLinker.getExternalDeclarationFileName(declaration) + }, onlyBitcode) + + fun addNativeRuntime(onlyBitcode: Boolean = false) = + add(FileOrigin.StdlibRuntime, onlyBitcode) + + private fun computeFileOrigin(packageFragment: IrPackageFragment, filePathGetter: () -> String): FileOrigin { + return if (packageFragment.isFunctionInterfaceFile) + FileOrigin.StdlibKFunctionImpl + else { + val library = when (val origin = packageFragment.packageFragmentDescriptor.llvmSymbolOrigin) { + CurrentKlibModuleOrigin -> config.libraryToCache?.klib?.takeIf { config.producePerFileCache } + else -> (origin as DeserializedKlibModuleOrigin).library + } + when { + library == null -> FileOrigin.CurrentFile + packageFragment.packageFragmentDescriptor.containingDeclaration.isFromInteropLibrary() -> + FileOrigin.EntireModule(library) + else -> FileOrigin.CertainFile(library, packageFragment.fqName.asString(), filePathGetter()) + } + } + } + + private fun add(origin: FileOrigin, onlyBitcode: Boolean = false) { + val libraryFile = when (origin) { + FileOrigin.CurrentFile -> return + is FileOrigin.EntireModule -> null + is FileOrigin.CertainFile -> LibraryFile(origin.library, origin.fqName, origin.filePath) + FileOrigin.StdlibRuntime -> stdlibRuntime + FileOrigin.StdlibKFunctionImpl -> stdlibKFunctionImpl + } + val library = libraryFile?.library ?: (origin as FileOrigin.EntireModule).library + if (library !in allLibraries) + error("Library (${library.libraryName}) is used but not requested.\nRequested libraries: ${allLibraries.joinToString { it.libraryName }}") + + var isNewDependency = usedBitcode.add(library) + if (!onlyBitcode) { + isNewDependency = isNewDependency || usedNativeDependencies.add(library) + } + + libraryFile?.let { + isNewDependency = isNewDependency || usedBitcodeOfFile.add(it) + } + + require(!(sealed && isNewDependency)) { "The dependencies have been sealed off" } + } + + fun bitcodeIsUsed(library: KonanLibrary) = library in usedBitcode + + fun usedBitcode(): List = usedBitcodeOfFile.toList() + + private val topSortedLibraries by lazy { + context.config.resolvedLibraries.getFullList(TopologicalLibraryOrder).map { it as KonanLibrary } + } + + private inner class CachedBitcodeDependenciesComputer { + private val allLibraries = topSortedLibraries.associateBy { it.uniqueName } + private val usedBitcode = usedBitcode().groupBy { it.library } + + private val moduleDependencies = mutableSetOf() + private val fileDependencies = mutableMapOf>() + + val allDependencies: List + + init { + val immediateBitcodeDependencies = topSortedLibraries + .filter { (!it.isDefault && !context.config.purgeUserLibs) || bitcodeIsUsed(it) } + val moduleDeserializers = context.irLinker.moduleDeserializers.values.associateBy { it.klib } + for (library in immediateBitcodeDependencies) { + if (library == context.config.libraryToCache?.klib) continue + val cache = context.config.cachedLibraries.getLibraryCache(library) + + if (cache != null) { + val filesUsed = buildList { + usedBitcode[library]?.forEach { + add(CacheSupport.cacheFileId(it.fqName, it.filePath)) + } + val moduleDeserializer = moduleDeserializers[library] + if (moduleDeserializer == null) { + require(library.isInteropLibrary()) { "No module deserializer for cached library ${library.uniqueName}" } + } else { + moduleDeserializer.eagerInitializedFiles.forEach { + add(CacheSupport.cacheFileId(it.fqName.asString(), it.path)) + } + } + } + + if (filesUsed.isEmpty()) { + // This is the case when we depend on the whole module rather than on a number of files. + moduleDependencies.add(library) + addAllDependencies(cache) + } else { + fileDependencies.getOrPut(library) { mutableSetOf() }.addAll(filesUsed) + addDependencies(cache, filesUsed) + } + } + } + + allDependencies = moduleDependencies.map { CachedBitcodeDependency.WholeModule(it) } + + fileDependencies.filterNot { it.key in moduleDependencies } + .map { (library, files) -> CachedBitcodeDependency.CertainFiles(library, files.toList()) } + } + + private fun addAllDependencies(cachedLibrary: CachedLibraries.Cache) { + cachedLibrary.bitcodeDependencies.forEach { addDependency(it) } + } + + private fun addDependencies(cachedLibrary: CachedLibraries.Cache, files: List) = when (cachedLibrary) { + is CachedLibraries.Cache.Monolithic -> addAllDependencies(cachedLibrary) + + is CachedLibraries.Cache.PerFile -> + files.forEach { file -> + cachedLibrary.getFileDependencies(file).forEach { addDependency(it) } + } + } + + private fun addDependency(dependency: CachedLibraries.BitcodeDependency) { + val dependencyLib = allLibraries[dependency.libName] + ?: error("Bitcode dependency to an unknown library: ${dependency.libName}") + if (dependencyLib in moduleDependencies) return + val cachedDependency = context.config.cachedLibraries.getLibraryCache(dependencyLib) + ?: error("Library ${dependency.libName} is expected to be cached") + + when (dependency) { + is CachedLibraries.BitcodeDependency.WholeModule -> { + moduleDependencies.add(dependencyLib) + addAllDependencies(cachedDependency) + } + is CachedLibraries.BitcodeDependency.CertainFiles -> { + val handledFiles = fileDependencies.getOrPut(dependencyLib) { mutableSetOf() } + val notHandledFiles = dependency.files.toMutableSet() + notHandledFiles.removeAll(handledFiles) + handledFiles.addAll(notHandledFiles) + if (notHandledFiles.isNotEmpty()) + addDependencies(cachedDependency, notHandledFiles.toList()) + } + } + } + } + + private inner class Dependencies { + val allCachedBitcodeDependencies = CachedBitcodeDependenciesComputer().allDependencies + + val nativeDependenciesToLink = topSortedLibraries.filter { (!it.isDefault && !context.config.purgeUserLibs) || it in usedNativeDependencies } + + val allNativeDependencies = (nativeDependenciesToLink + + allCachedBitcodeDependencies.map { it.library } // Native dependencies are per library + ).distinct() + + val allBitcodeDependencies: List = run { + val allBitcodeDependencies = mutableMapOf() + for (library in context.librariesWithDependencies) { + if (context.config.cachedLibraries.getLibraryCache(library) == null || library == context.config.libraryToCache?.klib) + allBitcodeDependencies[library] = CachedBitcodeDependency.WholeModule(library) + } + for (dependency in allCachedBitcodeDependencies) + allBitcodeDependencies[dependency.library] = dependency + // This list is used in particular to build the libraries' initializers chain. + // The initializers must be called in the topological order, so make sure that the + // libraries list being returned is also toposorted. + topSortedLibraries.mapNotNull { allBitcodeDependencies[it] } + } + + val bitcodeToLink = topSortedLibraries.filter { shouldContainBitcode(it) } + + private fun shouldContainBitcode(library: KonanLibrary): Boolean { + if (!generationState.llvmModuleSpecification.containsLibrary(library)) { + return false + } + + if (!generationState.llvmModuleSpecification.isFinal) { + return true + } + + // Apply some DCE: + return (!library.isDefault && !context.config.purgeUserLibs) || bitcodeIsUsed(library) + } + } + + private val dependencies by lazy { + sealed = true + + Dependencies() + } + + val allCachedBitcodeDependencies get() = dependencies.allCachedBitcodeDependencies + val nativeDependenciesToLink get() = dependencies.nativeDependenciesToLink + val allNativeDependencies get() = dependencies.allNativeDependencies + val allBitcodeDependencies get() = dependencies.allBitcodeDependencies + val bitcodeToLink get() = dependencies.bitcodeToLink +} \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt index 75e9943e6bf..c861b9ad870 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt @@ -1,7 +1,6 @@ package org.jetbrains.kotlin.backend.konan import org.jetbrains.kotlin.backend.konan.driver.PhaseContext -import org.jetbrains.kotlin.backend.konan.llvm.Llvm import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer import org.jetbrains.kotlin.backend.konan.serialization.EagerInitializedPropertySerializer import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer @@ -62,7 +61,7 @@ internal class CacheStorage(val generationState: NativeGenerationState) { private fun saveCacheBitcodeDependencies() { val libraryToCache = config.cacheSupport.libraryToCache!! - val usedBitcode = generationState.llvmImports.usedBitcode().groupBy { it.library } + val usedBitcode = generationState.dependenciesTracker.usedBitcode().groupBy { it.library } val bitcodeModuleDependencies = mutableListOf() val bitcodeFileDependencies = mutableListOf() val strategy = libraryToCache.strategy as? CacheDeserializationStrategy.SingleFile @@ -71,7 +70,7 @@ internal class CacheStorage(val generationState: NativeGenerationState) { .forEach { library -> require(library is KonanLibrary) val filesUsed = usedBitcode[library] - if (filesUsed == null && generationState.llvmImports.bitcodeIsUsed(library) + if (filesUsed == null && generationState.dependenciesTracker.bitcodeIsUsed(library) && library != libraryToCache.klib /* Skip loops */) { // Dependency on the entire library. bitcodeModuleDependencies.add("${library.uniqueName}${CachedLibraries.DEPENDENCIES_DELIMITER}") @@ -113,13 +112,13 @@ internal class Linker(val generationState: NativeGenerationState) { private val debug = config.debug || config.lightDebug fun link(objectFiles: List) { - val nativeDependencies = generationState.llvm.nativeDependenciesToLink + val nativeDependencies = generationState.dependenciesTracker.nativeDependenciesToLink val includedBinariesLibraries = config.libraryToCache?.let { listOf(it.klib) } ?: nativeDependencies.filterNot { config.cachedLibraries.isLibraryCached(it) } val includedBinaries = includedBinariesLibraries.map { (it as? KonanLibrary)?.includedPaths.orEmpty() }.flatten() - val libraryProvidedLinkerFlags = generationState.llvm.allNativeDependencies.map { it.linkerOpts }.flatten() + val libraryProvidedLinkerFlags = generationState.dependenciesTracker.allNativeDependencies.map { it.linkerOpts }.flatten() runLinker(objectFiles, includedBinaries, libraryProvidedLinkerFlags) } @@ -262,7 +261,7 @@ private fun determineCachesToLink(generationState: NativeGenerationState): Cache val staticCaches = mutableListOf() val dynamicCaches = mutableListOf() - generationState.llvm.allCachedBitcodeDependencies.forEach { dependency -> + generationState.dependenciesTracker.allCachedBitcodeDependencies.forEach { dependency -> val library = dependency.library val currentBinaryContainsLibrary = generationState.llvmModuleSpecification.containsLibrary(library) val cache = generationState.config.cachedLibraries.getLibraryCache(library) @@ -277,7 +276,7 @@ private fun determineCachesToLink(generationState: NativeGenerationState): Cache CachedLibraries.Kind.STATIC -> staticCaches } - list += if (dependency is Llvm.CachedBitcodeDependency.CertainFiles && cache is CachedLibraries.Cache.PerFile) + list += if (dependency is DependenciesTracker.CachedBitcodeDependency.CertainFiles && cache is CachedLibraries.Cache.PerFile) dependency.files.map { cache.getFileBinaryPath(it) } else cache.binariesPaths } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt index 9f5d740b4ee..0541404aad6 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt @@ -6,9 +6,7 @@ package org.jetbrains.kotlin.backend.konan import llvm.* -import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext -import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport @@ -16,12 +14,8 @@ import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields import org.jetbrains.kotlin.backend.konan.serialization.SerializedEagerInitializedFile import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.util.getPackageFragment import org.jetbrains.kotlin.konan.TempFiles import org.jetbrains.kotlin.konan.file.File -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin -import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin -import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int) @@ -90,12 +84,13 @@ internal class NativeGenerationState( val producedLlvmModuleContainsStdlib get() = llvmModuleSpecification.containsModule(context.stdlibModule) + val dependenciesTracker = DependenciesTracker(this) + private val runtimeDelegate = lazy { Runtime(llvmContext, config.distribution.compilerInterface(config.target)) } private val llvmDelegate = lazy { Llvm(this, LLVMModuleCreateWithNameInContext("out", llvmContext)!!) } private val debugInfoDelegate = lazy { DebugInfo(this) } val llvmContext = LLVMContextCreate()!! - val llvmImports = Llvm.ImportsImpl(context) val runtime by runtimeDelegate val llvm by llvmDelegate val debugInfo by debugInfoDelegate @@ -110,25 +105,6 @@ internal class NativeGenerationState( lateinit var objCExport: ObjCExport - fun computeOrigin(declaration: IrDeclaration): CompiledKlibFileOrigin { - val packageFragment = declaration.getPackageFragment() - return if (packageFragment.isFunctionInterfaceFile) - CompiledKlibFileOrigin.StdlibKFunctionImpl - else { - val library = when (val origin = declaration.llvmSymbolOrigin) { - CurrentKlibModuleOrigin -> config.libraryToCache?.klib?.takeIf { config.producePerFileCache } - else -> (origin as DeserializedKlibModuleOrigin).library - } - when { - library == null -> CompiledKlibFileOrigin.CurrentFile - packageFragment.packageFragmentDescriptor.containingDeclaration.isFromInteropLibrary() -> - CompiledKlibFileOrigin.EntireModule(library) - else -> CompiledKlibFileOrigin.CertainFile(library, packageFragment.fqName.asString(), - context.irLinker.getExternalDeclarationFileName(declaration)) - } - } - } - fun hasDebugInfo() = debugInfoDelegate.isInitialized() fun verifyBitCode() { 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 5279c263bca..11deaa20d8c 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 @@ -17,7 +17,6 @@ import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.konan.target.CompilerOutputKind -import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin import org.jetbrains.kotlin.name.FqName internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt index 3686a57d571..f62b322667c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.konan.driver.PhaseEngine import org.jetbrains.kotlin.backend.konan.driver.runPhaseInParentContext import org.jetbrains.kotlin.backend.konan.llvm.linkBitcodeDependenciesPhase import org.jetbrains.kotlin.backend.konan.llvm.printBitcodePhase -import org.jetbrains.kotlin.backend.konan.llvm.standardLlvmSymbolsOrigin import org.jetbrains.kotlin.backend.konan.llvm.verifyBitcodePhase import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.ir.declarations.IrClass @@ -20,8 +19,6 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.path import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.konan.target.CompilerOutputKind -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin -import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin internal fun PhaseEngine.runFrontend(config: KonanConfig, environment: KotlinCoreEnvironment): FrontendPhaseOutput.Full? { val frontendOutput = useContext(FrontendContextImpl(config)) { it.runFrontend(environment) } @@ -102,10 +99,8 @@ internal fun PhaseEngine.processModuleFragments( module.files += functionInterfaceFiles if (generationState.shouldLinkRuntimeNativeLibraries) { - val stdlib = (context.standardLlvmSymbolsOrigin as DeserializedKlibModuleOrigin).library filesReferencedByNativeRuntime.forEach { - generationState.llvmImports.add( - CompiledKlibFileOrigin.CertainFile(stdlib, it.fqName.asString(), it.path)) + generationState.dependenciesTracker.add(it) } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index e686a3437f5..54027a4886e 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -17,7 +17,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.ThreadState.Runnable import org.jetbrains.kotlin.backend.konan.llvm.objc.* import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.konan.ForeignExceptionMode @@ -1265,11 +1264,10 @@ internal abstract class FunctionGenerationContext( assert(!irClass.isInterface) return if (irClass.isExternalObjCClass()) { - val origin = generationState.computeOrigin(irClass) - + llvm.dependenciesTracker.add(irClass) if (irClass.isObjCMetaClass()) { val name = irClass.descriptor.getExternalObjCMetaClassBinaryName() - val objCClass = getObjCClass(name, origin) + val objCClass = getObjCClass(name) val getClass = llvm.externalNativeRuntimeFunction( "object_getClass", @@ -1278,7 +1276,7 @@ internal abstract class FunctionGenerationContext( ) call(getClass, listOf(objCClass), exceptionHandler = exceptionHandler) } else { - getObjCClass(irClass.descriptor.getExternalObjCClassBinaryName(), origin) + getObjCClass(irClass.descriptor.getExternalObjCClassBinaryName()) } } else { if (irClass.isObjCMetaClass()) { @@ -1302,9 +1300,11 @@ internal abstract class FunctionGenerationContext( } } - fun getObjCClass(binaryName: String, origin: CompiledKlibFileOrigin): LLVMValueRef { - llvm.imports.add(origin) - return load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm) + private fun getObjCClass(binaryName: String) = load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm) + + fun getObjCClassFromNativeRuntime(binaryName: String): LLVMValueRef { + llvm.dependenciesTracker.addNativeRuntime() + return getObjCClass(binaryName) } fun resetDebugLocation() { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index e2b9b24bdb0..807aa00f4f2 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -8,24 +8,13 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.toCValues import kotlinx.cinterop.toKString import llvm.* -import org.jetbrains.kotlin.backend.common.atMostOne import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary -import org.jetbrains.kotlin.library.metadata.resolver.TopologicalLibraryOrder -import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin import org.jetbrains.kotlin.descriptors.konan.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin -import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin -import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin -import org.jetbrains.kotlin.library.uniqueName -import org.jetbrains.kotlin.name.FqName import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty @@ -221,7 +210,7 @@ internal interface ContextUtils : RuntimeAware { this.computePrivateTypeInfoSymbolName(context.irLinker.getExternalDeclarationFileName(this)) } - constPointer(importGlobal(typeInfoSymbolName, runtime.typeInfoType, generationState.computeOrigin(this))) + constPointer(importGlobal(typeInfoSymbolName, runtime.typeInfoType, this)) } else { generationState.llvmDeclarations.forClass(this).typeInfo } @@ -348,7 +337,7 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu } internal fun externalFunction(llvmFunctionProto: LlvmFunctionProto): LlvmCallable { - this.imports.add(llvmFunctionProto.origin, onlyBitcode = llvmFunctionProto.independent) + this.dependenciesTracker.add(llvmFunctionProto.origin, onlyBitcode = llvmFunctionProto.independent) val found = LLVMGetNamedFunction(module, llvmFunctionProto.name) if (found != null) { assert(getFunctionType(found) == llvmFunctionProto.llvmFunctionType) { @@ -372,208 +361,14 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu isVararg: Boolean = false ) = externalFunction( LlvmFunctionProto(name, returnType, parameterTypes, functionAttributes, - origin = CompiledKlibFileOrigin.StdlibRuntime, + origin = FunctionOrigin.FromNativeRuntime, isVararg, independent = false) ) internal fun externalNativeRuntimeFunction(name: String, signature: LlvmFunctionSignature) = externalNativeRuntimeFunction(name, signature.returnType, signature.parameterTypes, signature.functionAttributes, signature.isVararg) - val imports get() = generationState.llvmImports - - class ImportsImpl(private val context: Context) : LlvmImports { - - private val usedBitcode = mutableSetOf() - private val usedNativeDependencies = mutableSetOf() - - private val usedBitcodeOfFile = mutableSetOf() - - private val allLibraries by lazy { context.librariesWithDependencies.toSet() } - - private fun findStdlibFile(fqName: FqName, fileName: String): LlvmImports.LibraryFile { - val stdlib = (context.standardLlvmSymbolsOrigin as? DeserializedKlibModuleOrigin)?.library - ?: error("Can't find stdlib") - val stdlibDeserializer = context.irLinker.moduleDeserializers[context.stdlibModule] - ?: error("No deserializer for stdlib") - val file = stdlibDeserializer.files.atMostOne { it.fqName == fqName && it.name == fileName } - ?: error("Can't find $fqName:$fileName in stdlib") - return LlvmImports.LibraryFile(stdlib, file.fqName.asString(), file.path) - } - - private val stdlibRuntime by lazy { findStdlibFile(KonanFqNames.internalPackageName, "Runtime.kt") } - private val stdlibKFunctionImpl by lazy { findStdlibFile(KonanFqNames.internalPackageName, "KFunctionImpl.kt") } - - override fun add(origin: CompiledKlibFileOrigin, onlyBitcode: Boolean) { - val libraryFile = when (origin) { - CompiledKlibFileOrigin.CurrentFile -> return - is CompiledKlibFileOrigin.EntireModule -> null - is CompiledKlibFileOrigin.CertainFile -> LlvmImports.LibraryFile(origin.library, origin.fqName, origin.filePath) - CompiledKlibFileOrigin.StdlibRuntime -> stdlibRuntime - CompiledKlibFileOrigin.StdlibKFunctionImpl -> stdlibKFunctionImpl - } - val library = libraryFile?.library ?: (origin as CompiledKlibFileOrigin.EntireModule).library - if (library !in allLibraries) - error("Library (${library.libraryName}) is used but not requested.\nRequested libraries: ${allLibraries.joinToString { it.libraryName }}") - - usedBitcode.add(library) - if (!onlyBitcode) { - usedNativeDependencies.add(library) - } - - libraryFile?.let { usedBitcodeOfFile.add(it) } - } - - override fun bitcodeIsUsed(library: KonanLibrary) = library in usedBitcode - - override fun nativeDependenciesAreUsed(library: KonanLibrary) = library in usedNativeDependencies - - override fun usedBitcode(): List = usedBitcodeOfFile.toList() - } - - val nativeDependenciesToLink: List by lazy { - context.config.resolvedLibraries - .getFullList(TopologicalLibraryOrder) - .map { it as KonanLibrary } - .filter { - (!it.isDefault && !context.config.purgeUserLibs) || imports.nativeDependenciesAreUsed(it) - } - } - - private val immediateBitcodeDependencies: List by lazy { - context.config.resolvedLibraries.getFullList(TopologicalLibraryOrder).map { it as KonanLibrary } - .filter { (!it.isDefault && !context.config.purgeUserLibs) || imports.bitcodeIsUsed(it) } - } - - sealed class CachedBitcodeDependency(val library: KonanLibrary) { - class WholeModule(library: KonanLibrary) : CachedBitcodeDependency(library) - - class CertainFiles(library: KonanLibrary, val files: List) : CachedBitcodeDependency(library) - } - - private inner class CachedBitcodeDependenciesComputer { - private val allLibraries = context.config.resolvedLibraries.getFullList().associateBy { it.uniqueName } - private val usedBitcode = imports.usedBitcode().groupBy { it.library } - - private val moduleDependencies = mutableSetOf() - private val fileDependencies = mutableMapOf>() - - val allDependencies: List - - init { - val moduleDeserializers = context.irLinker.moduleDeserializers.values.associateBy { it.klib } - for (library in immediateBitcodeDependencies) { - if (library == context.config.libraryToCache?.klib) continue - val cache = context.config.cachedLibraries.getLibraryCache(library) - - if (cache != null) { - val filesUsed = buildList { - usedBitcode[library]?.forEach { - add(CacheSupport.cacheFileId(it.fqName, it.filePath)) - } - val moduleDeserializer = moduleDeserializers[library] - if (moduleDeserializer == null) { - require(library.isInteropLibrary()) { "No module deserializer for cached library ${library.uniqueName}" } - } else { - moduleDeserializer.eagerInitializedFiles.forEach { - add(CacheSupport.cacheFileId(it.fqName.asString(), it.path)) - } - } - } - - if (filesUsed.isEmpty()) { - // This is the case when we depend on the whole module rather than on a number of files. - moduleDependencies.add(library) - addAllDependencies(cache) - } else { - fileDependencies.getOrPut(library) { mutableSetOf() }.addAll(filesUsed) - addDependencies(cache, filesUsed) - } - } - } - - allDependencies = moduleDependencies.map { CachedBitcodeDependency.WholeModule(it) } + - fileDependencies.filterNot { it.key in moduleDependencies } - .map { (library, files) -> CachedBitcodeDependency.CertainFiles(library, files.toList()) } - } - - private fun addAllDependencies(cachedLibrary: CachedLibraries.Cache) { - cachedLibrary.bitcodeDependencies.forEach { addDependency(it) } - } - - private fun addDependencies(cachedLibrary: CachedLibraries.Cache, files: List) = when (cachedLibrary) { - is CachedLibraries.Cache.Monolithic -> addAllDependencies(cachedLibrary) - - is CachedLibraries.Cache.PerFile -> - files.forEach { file -> - cachedLibrary.getFileDependencies(file).forEach { addDependency(it) } - } - } - - private fun addDependency(dependency: CachedLibraries.BitcodeDependency) { - val dependencyLib = (allLibraries[dependency.libName] - ?: error("Bitcode dependency to an unknown library: ${dependency.libName}")) as KonanLibrary - if (dependencyLib in moduleDependencies) return - val cachedDependency = context.config.cachedLibraries.getLibraryCache(dependencyLib) - ?: error("Library ${dependency.libName} is expected to be cached") - - when (dependency) { - is CachedLibraries.BitcodeDependency.WholeModule -> { - moduleDependencies.add(dependencyLib) - addAllDependencies(cachedDependency) - } - is CachedLibraries.BitcodeDependency.CertainFiles -> { - val handledFiles = fileDependencies.getOrPut(dependencyLib) { mutableSetOf() } - val notHandledFiles = dependency.files.toMutableSet() - notHandledFiles.removeAll(handledFiles) - handledFiles.addAll(notHandledFiles) - if (notHandledFiles.isNotEmpty()) - addDependencies(cachedDependency, notHandledFiles.toList()) - } - } - } - } - - val allCachedBitcodeDependencies: List by lazy { - CachedBitcodeDependenciesComputer().allDependencies - } - - val allNativeDependencies: List by lazy { - (nativeDependenciesToLink + allCachedBitcodeDependencies.map { it.library } /* Native dependencies are per library */).distinct() - } - - val allBitcodeDependencies: List by lazy { - val allBitcodeDependencies = mutableMapOf() - for (library in context.librariesWithDependencies) { - if (context.config.cachedLibraries.getLibraryCache(library) == null || library == context.config.libraryToCache?.klib) - allBitcodeDependencies[library] = CachedBitcodeDependency.WholeModule(library) - } - for (dependency in allCachedBitcodeDependencies) - allBitcodeDependencies[dependency.library] = dependency - // This list is used in particular to build the libraries' initializers chain. - // The initializers must be called in the topological order, so make sure that the - // libraries list being returned is also toposorted. - context.config.resolvedLibraries - .getFullList(TopologicalLibraryOrder) - .mapNotNull { allBitcodeDependencies[it as KonanLibrary] } - } - - val bitcodeToLink: List by lazy { - context.config.resolvedLibraries.getFullList(TopologicalLibraryOrder).map { it as KonanLibrary } - .filter { shouldContainBitcode(it) } - } - - private fun shouldContainBitcode(library: KonanLibrary): Boolean { - if (!generationState.llvmModuleSpecification.containsLibrary(library)) { - return false - } - - if (!generationState.llvmModuleSpecification.isFinal) { - return true - } - - // Apply some DCE: - return (!library.isDefault && !context.config.purgeUserLibs) || imports.bitcodeIsUsed(library) - } + val dependenciesTracker get() = generationState.dependenciesTracker val additionalProducedBitcodeFiles = mutableListOf() diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Imports.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Imports.kt index 0c13c4b8157..1f0a7fb7ae5 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Imports.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Imports.kt @@ -8,23 +8,11 @@ package org.jetbrains.kotlin.backend.konan.llvm import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin import org.jetbrains.kotlin.library.metadata.SyntheticModulesOrigin import org.jetbrains.kotlin.library.metadata.klibModuleOrigin -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin -import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.resolve.descriptorUtil.module -internal interface LlvmImports { - data class LibraryFile(val library: KotlinLibrary, val fqName: String, val filePath: String) - - fun add(origin: CompiledKlibFileOrigin, onlyBitcode: Boolean = false) - fun bitcodeIsUsed(library: KonanLibrary): Boolean - fun nativeDependenciesAreUsed(library: KonanLibrary): Boolean - fun usedBitcode(): List -} - internal val DeclarationDescriptor.llvmSymbolOrigin: CompiledKlibModuleOrigin get() { assert(!this.isExpectMember) { this } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 92966794d19..71544d426af 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -22,7 +22,6 @@ import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_STATIC_STANDA import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET @@ -1639,7 +1638,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, } else if (dstClass.isObjCProtocolClass()) { // Note: it is not clear whether this class should be looked up this way. // clang does the same, however swiftc uses dynamic lookup. - val protocolClass = functionGenerationContext.getObjCClass("Protocol", CompiledKlibFileOrigin.StdlibRuntime) + val protocolClass = functionGenerationContext.getObjCClassFromNativeRuntime("Protocol") call( llvm.Kotlin_Interop_IsObjectKindOfClass, listOf(objCObject, protocolClass) @@ -2494,7 +2493,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, val protocolGetterProto = LlvmFunctionProto( protocolGetterName, LlvmRetType(llvm.int8PtrType), - origin = generationState.computeOrigin(irClass), + origin = FunctionOrigin.OwnedBy(irClass), independent = true // Protocol is header-only declaration. ) val protocolGetter = llvm.externalFunction(protocolGetterProto) @@ -2687,7 +2686,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, llvm.otherStaticInitializers += initializer } else { - generationState.llvmImports.add(CompiledKlibFileOrigin.StdlibRuntime) + generationState.dependenciesTracker.addNativeRuntime() // Define a strong runtime global. It'll overrule a weak global defined in a statically linked runtime. val global = llvm.staticData.placeGlobal(name, value, true) @@ -2757,7 +2756,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, //-------------------------------------------------------------------------// fun appendStaticInitializers() { // Note: the list of libraries is topologically sorted (in order for initializers to be called correctly). - val dependencies = (llvm.allBitcodeDependencies + listOf(null)/* Null for "current" non-library module */) + val dependencies = (generationState.dependenciesTracker.allBitcodeDependencies + listOf(null)/* Null for "current" non-library module */) val libraryToInitializers = dependencies.associate { it?.library to mutableListOf() } @@ -2812,9 +2811,9 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, is CachedLibraries.Cache.Monolithic -> listOf(addCtorFunction(ctorName)) is CachedLibraries.Cache.PerFile -> { val files = when (dependency) { - is Llvm.CachedBitcodeDependency.WholeModule -> + is DependenciesTracker.CachedBitcodeDependency.WholeModule -> context.irLinker.klibToModuleDeserializerMap[library]!!.sortedFileIds - is Llvm.CachedBitcodeDependency.CertainFiles -> + is DependenciesTracker.CachedBitcodeDependency.CertainFiles -> dependency.files } files.map { addCtorFunction(fileCtorName(library.uniqueName, it)) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt index cb4cea18d38..d7ac3b307b1 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinObjCClassInfoGenerator.kt @@ -28,11 +28,11 @@ internal class KotlinObjCClassInfoGenerator(override val generationState: Native val classMethods = companionObject?.generateMethodDescs().orEmpty() val superclassName = irClass.getSuperClassNotAny()!!.let { - llvm.imports.add(generationState.computeOrigin(it)) + llvm.dependenciesTracker.add(it) it.descriptor.getExternalObjCClassBinaryName() } val protocolNames = irClass.getSuperInterfaces().map { - llvm.imports.add(generationState.computeOrigin(it)) + llvm.dependenciesTracker.add(it) it.name.asString().removeSuffix("Protocol") } @@ -158,11 +158,7 @@ internal class KotlinObjCClassInfoGenerator(override val generationState: Native internal fun CodeGenerator.kotlinObjCClassInfo(irClass: IrClass): LLVMValueRef { require(irClass.isKotlinObjCClass()) return if (isExternal(irClass)) { - importGlobal( - irClass.kotlinObjCClassInfoSymbolName, - runtime.kotlinObjCClassInfo, - generationState.computeOrigin(irClass) - ) + importGlobal(irClass.kotlinObjCClassInfoSymbolName, runtime.kotlinObjCClassInfo, irClass) } else { llvmDeclarations.forClass(irClass).objCDeclarations!!.classInfoGlobal.llvmGlobal } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt index d70fed12445..d7ab6b51102 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/KotlinStaticData.kt @@ -104,8 +104,7 @@ internal class KotlinStaticData(override val generationState: NativeGenerationSt UniqueKind.EMPTY_ARRAY -> context.ir.symbols.array.owner } return if (isExternal(descriptor)) { - constPointer( - importGlobal(kind.llvmName, runtime.objHeaderType, generationState.computeOrigin(descriptor))) + constPointer(importGlobal(kind.llvmName, runtime.objHeaderType, descriptor)) } else { generationState.llvmDeclarations.forUnique(kind).pointer } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmFunctionPrototype.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmFunctionPrototype.kt index 13f7b478b46..0862b159119 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmFunctionPrototype.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmFunctionPrototype.kt @@ -11,10 +11,8 @@ import kotlinx.cinterop.memScoped import llvm.* import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.RuntimeNames -import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin -import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.util.hasAnnotation @@ -149,6 +147,13 @@ internal open class LlvmFunctionSignature( } } +internal sealed class FunctionOrigin { + object FromNativeRuntime : FunctionOrigin() + + class OwnedBy(val declaration: IrDeclaration) : FunctionOrigin() +} + + /** * Prototype of a LLVM function that is not tied to a specific LLVM module. */ @@ -157,14 +162,14 @@ internal class LlvmFunctionProto( returnType: LlvmRetType, parameterTypes: List = emptyList(), functionAttributes: List = emptyList(), - val origin: CompiledKlibFileOrigin, + val origin: FunctionOrigin, isVararg: Boolean = false, val independent: Boolean = false, ) : LlvmFunctionSignature(returnType, parameterTypes, isVararg, functionAttributes) { constructor( name: String, signature: LlvmFunctionSignature, - origin: CompiledKlibFileOrigin, + origin: FunctionOrigin, independent: Boolean = false, ) : this(name, signature.returnType, signature.parameterTypes, signature.functionAttributes, origin, signature.isVararg, independent) @@ -173,7 +178,7 @@ internal class LlvmFunctionProto( returnType = contextUtils.getLlvmFunctionReturnType(irFunction), parameterTypes = contextUtils.getLlvmFunctionParameterTypes(irFunction), functionAttributes = inferFunctionAttributes(contextUtils, irFunction), - origin = contextUtils.generationState.computeOrigin(irFunction), + origin = FunctionOrigin.OwnedBy(irFunction), independent = irFunction.hasAnnotation(RuntimeNames.independent) ) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt index 264c7277132..7b76b2ce503 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.backend.konan.llvm import kotlinx.cinterop.* import llvm.* -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin +import org.jetbrains.kotlin.ir.declarations.IrDeclaration internal val LLVMValueRef.type: LLVMTypeRef get() = LLVMTypeOf(this)!! @@ -170,7 +170,7 @@ internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported: return LLVMAddGlobal(llvm.module, type, name)!! } -private fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef): LLVMValueRef { +internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef): LLVMValueRef { val found = LLVMGetNamedGlobal(llvm.module, name) return if (found == null) addGlobal(name, type, isExported = false) @@ -181,13 +181,13 @@ private fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef): LLVMValu } } -internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: CompiledKlibFileOrigin) = - importGlobal(name, type).also { llvm.imports.add(origin) } +internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, declaration: IrDeclaration) = + importGlobal(name, type).also { llvm.dependenciesTracker.add(declaration) } internal fun ContextUtils.importObjCGlobal(name: String, type: LLVMTypeRef) = importGlobal(name, type) internal fun ContextUtils.importNativeRuntimeGlobal(name: String, type: LLVMTypeRef) = - importGlobal(name, type, CompiledKlibFileOrigin.StdlibRuntime) + importGlobal(name, type).also { llvm.dependenciesTracker.addNativeRuntime() } internal abstract class AddressAccess { abstract fun getAddress(generationContext: FunctionGenerationContext?): LLVMValueRef diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index ad00d3d3704..79bb1f6e03f 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.backend.konan.objcexport.* import org.jetbrains.kotlin.backend.konan.serialization.resolveFakeOverrideMaybeAbstract import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrClassReference @@ -464,10 +463,9 @@ internal class ObjCExportCodeGenerator( emitSpecialClassesConvertions() // Replace runtime global with weak linkage: - replaceExternalWeakOrCommonGlobal( + replaceExternalWeakOrCommonGlobalFromNativeRuntime( "Kotlin_ObjCInterop_uniquePrefix", - codegen.staticData.cStringLiteral(namer.topLevelNamePrefix), - CompiledKlibFileOrigin.StdlibRuntime + codegen.staticData.cStringLiteral(namer.topLevelNamePrefix) ) emitSelectorsHolder() @@ -513,9 +511,8 @@ internal class ObjCExportCodeGenerator( val sortedAdaptersPointer = staticData.placeGlobalConstArray("", type, sortedAdapters) // Note: this globals replace runtime globals with weak linkage: - val origin = CompiledKlibFileOrigin.StdlibRuntime - replaceExternalWeakOrCommonGlobal(prefix, sortedAdaptersPointer, origin) - replaceExternalWeakOrCommonGlobal("${prefix}Num", llvm.constInt32(sortedAdapters.size), origin) + replaceExternalWeakOrCommonGlobalFromNativeRuntime(prefix, sortedAdaptersPointer) + replaceExternalWeakOrCommonGlobalFromNativeRuntime("${prefix}Num", llvm.constInt32(sortedAdapters.size)) } } @@ -523,10 +520,9 @@ internal class ObjCExportCodeGenerator( emitSortedAdapters(placedInterfaceAdapters, "Kotlin_ObjCExport_sortedProtocolAdapters") if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) { - replaceExternalWeakOrCommonGlobal( + replaceExternalWeakOrCommonGlobalFromNativeRuntime( "Kotlin_ObjCExport_initTypeAdapters", - llvm.constInt1(true), - CompiledKlibFileOrigin.StdlibRuntime + llvm.constInt1(true) ) } } @@ -692,15 +688,13 @@ internal class ObjCExportCodeGenerator( private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal( name: String, - value: ConstValue, - origin: CompiledKlibFileOrigin + value: ConstValue ) { // TODO: A similar mechanism is used in `IrToBitcode.overrideRuntimeGlobal`. Consider merging them. if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) { - val global = codegen.importGlobal(name, value.llvmType, origin) + val global = codegen.importGlobal(name, value.llvmType) externalGlobalInitializers[global] = value } else { - generationState.llvmImports.add(origin) val global = staticData.placeGlobal(name, value, isExported = true) if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) { @@ -714,6 +708,17 @@ private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal( } } +private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal( + name: String, + value: ConstValue, + declaration: IrDeclaration +) = replaceExternalWeakOrCommonGlobal(name, value).also { generationState.dependenciesTracker.add(declaration) } + +private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobalFromNativeRuntime( + name: String, + value: ConstValue +) = replaceExternalWeakOrCommonGlobal(name, value).also { generationState.dependenciesTracker.addNativeRuntime() } + private fun ObjCExportCodeGenerator.setObjCExportTypeInfo( irClass: IrClass, convertToRetained: ConstPointer? = null, @@ -731,7 +736,7 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo( replaceExternalWeakOrCommonGlobal( irClass.writableTypeInfoSymbolName, writableTypeInfoValue, - generationState.computeOrigin(irClass) + irClass ) } else { setOwnWritableTypeInfo(irClass, writableTypeInfoValue) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CachesAbiLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CachesAbiLowering.kt index 17a53f29dcb..bab900a4265 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CachesAbiLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CachesAbiLowering.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.NativeGenerationState import org.jetbrains.kotlin.backend.konan.NativeMapping import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName -import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.builders.* @@ -151,8 +150,7 @@ internal class ExportCachesAbiVisitor(val context: Context) : FileLoweringPass, internal class ImportCachesAbiTransformer(val generationState: NativeGenerationState) : FileLoweringPass, IrElementTransformerVoid() { private val cachesAbiSupport = generationState.context.cachesAbiSupport private val innerClassesSupport = generationState.context.innerClassesSupport - private val llvmImports = generationState.llvmImports - private val irLinker = generationState.context.irLinker + private val dependenciesTracker = generationState.dependenciesTracker override fun lower(irFile: IrFile) { irFile.transformChildrenVoid(this) @@ -171,7 +169,7 @@ internal class ImportCachesAbiTransformer(val generationState: NativeGenerationS irClass?.isInner == true && innerClassesSupport.getOuterThisField(irClass) == field -> { val accessor = cachesAbiSupport.getOuterThisAccessor(irClass) - llvmImports.add(generationState.computeOrigin(irClass)) + dependenciesTracker.add(irClass) return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply { putValueArgument(0, expression.receiver) } @@ -179,7 +177,7 @@ internal class ImportCachesAbiTransformer(val generationState: NativeGenerationS property?.isLateinit == true -> { val accessor = cachesAbiSupport.getLateinitPropertyAccessor(property) - llvmImports.add(generationState.computeOrigin(property)) + dependenciesTracker.add(property) return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply { if (irClass != null) putValueArgument(0, expression.receiver) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt index 346618d267f..07b81112883 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt @@ -543,7 +543,7 @@ private class InteropLoweringPart1(val generationState: NativeGenerationState) : ): IrExpression = generateWithStubs(call) { if (method.parent !is IrClass) { // Category-provided. - generationState.llvmImports.add(generationState.computeOrigin(method)) + generationState.dependenciesTracker.add(method) } this.generateObjCCall( @@ -1011,7 +1011,7 @@ private class InteropTransformer( private fun generateCCall(expression: IrCall): IrExpression { val function = expression.symbol.owner - generationState.llvmImports.add(generationState.computeOrigin(function)) + generationState.dependenciesTracker.add(function) val exceptionMode = ForeignExceptionMode.byValue( function.konanLibrary?.manifestProperties?.getProperty(ForeignExceptionMode.manifestKey) )