[K/N][IR][codegen] Introduced DependenciesTracker
This commit is contained in:
-12
@@ -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()
|
||||
}
|
||||
+2
-2
@@ -119,7 +119,7 @@ private data class LlvmModules(
|
||||
private fun collectLlvmModules(generationState: NativeGenerationState, generatedBitcodeFiles: List<String>): 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)
|
||||
}
|
||||
|
||||
+269
@@ -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<String>) : CachedBitcodeDependency(library)
|
||||
}
|
||||
|
||||
private val config = generationState.config
|
||||
private val context = generationState.context
|
||||
|
||||
private val usedBitcode = mutableSetOf<KotlinLibrary>()
|
||||
private val usedNativeDependencies = mutableSetOf<KotlinLibrary>()
|
||||
private val usedBitcodeOfFile = mutableSetOf<LibraryFile>()
|
||||
|
||||
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<LibraryFile> = 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<KonanLibrary>()
|
||||
private val fileDependencies = mutableMapOf<KonanLibrary, MutableSet<String>>()
|
||||
|
||||
val allDependencies: List<CachedBitcodeDependency>
|
||||
|
||||
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<String>) = 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<CachedBitcodeDependency> = run {
|
||||
val allBitcodeDependencies = mutableMapOf<KonanLibrary, CachedBitcodeDependency>()
|
||||
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
|
||||
}
|
||||
+6
-7
@@ -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<String>()
|
||||
val bitcodeFileDependencies = mutableListOf<String>()
|
||||
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<ObjectFile>) {
|
||||
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<String>()
|
||||
val dynamicCaches = mutableListOf<String>()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
+2
-26
@@ -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() {
|
||||
|
||||
-1
@@ -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) {
|
||||
|
||||
+1
-6
@@ -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<PhaseContext>.runFrontend(config: KonanConfig, environment: KotlinCoreEnvironment): FrontendPhaseOutput.Full? {
|
||||
val frontendOutput = useContext(FrontendContextImpl(config)) { it.runFrontend(environment) }
|
||||
@@ -102,10 +99,8 @@ internal fun PhaseEngine<out Context>.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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -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() {
|
||||
|
||||
+4
-209
@@ -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<KotlinLibrary>()
|
||||
private val usedNativeDependencies = mutableSetOf<KotlinLibrary>()
|
||||
|
||||
private val usedBitcodeOfFile = mutableSetOf<LlvmImports.LibraryFile>()
|
||||
|
||||
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<LlvmImports.LibraryFile> = usedBitcodeOfFile.toList()
|
||||
}
|
||||
|
||||
val nativeDependenciesToLink: List<KonanLibrary> by lazy {
|
||||
context.config.resolvedLibraries
|
||||
.getFullList(TopologicalLibraryOrder)
|
||||
.map { it as KonanLibrary }
|
||||
.filter {
|
||||
(!it.isDefault && !context.config.purgeUserLibs) || imports.nativeDependenciesAreUsed(it)
|
||||
}
|
||||
}
|
||||
|
||||
private val immediateBitcodeDependencies: List<KonanLibrary> 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<String>) : 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<KonanLibrary>()
|
||||
private val fileDependencies = mutableMapOf<KonanLibrary, MutableSet<String>>()
|
||||
|
||||
val allDependencies: List<CachedBitcodeDependency>
|
||||
|
||||
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<String>) = 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<CachedBitcodeDependency> by lazy {
|
||||
CachedBitcodeDependenciesComputer().allDependencies
|
||||
}
|
||||
|
||||
val allNativeDependencies: List<KonanLibrary> by lazy {
|
||||
(nativeDependenciesToLink + allCachedBitcodeDependencies.map { it.library } /* Native dependencies are per library */).distinct()
|
||||
}
|
||||
|
||||
val allBitcodeDependencies: List<CachedBitcodeDependency> by lazy {
|
||||
val allBitcodeDependencies = mutableMapOf<KonanLibrary, CachedBitcodeDependency>()
|
||||
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<KonanLibrary> 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<String>()
|
||||
|
||||
|
||||
-12
@@ -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<LibraryFile>
|
||||
}
|
||||
|
||||
internal val DeclarationDescriptor.llvmSymbolOrigin: CompiledKlibModuleOrigin
|
||||
get() {
|
||||
assert(!this.isExpectMember) { this }
|
||||
|
||||
+6
-7
@@ -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<LLVMValueRef>() }
|
||||
|
||||
@@ -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)) }
|
||||
|
||||
+3
-7
@@ -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
|
||||
}
|
||||
|
||||
+1
-2
@@ -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
|
||||
}
|
||||
|
||||
+11
-6
@@ -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<LlvmParamType> = emptyList(),
|
||||
functionAttributes: List<LlvmFunctionAttribute> = 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)
|
||||
)
|
||||
}
|
||||
|
||||
+5
-5
@@ -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
|
||||
|
||||
+20
-15
@@ -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)
|
||||
|
||||
+3
-5
@@ -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)
|
||||
|
||||
+2
-2
@@ -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)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user