[K/N] Extract cache management in linker to a separate file

Also, more meaningful names.
This commit is contained in:
Sergey Bogolepov
2023-01-25 13:26:30 +02:00
committed by Space Team
parent 2f1e9844df
commit e6081e5851
2 changed files with 61 additions and 44 deletions
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.konan.target.LinkerOutputKind
/**
* Check if we should link static caches into an object file before running full linkage.
*/
internal fun shouldPerformPreLink(config: KonanConfig, caches: ResolvedCacheBinaries, linkerOutputKind: LinkerOutputKind): Boolean {
// Pre-link is only useful when producing static library. Otherwise its just a waste of time.
val isStaticLibrary = linkerOutputKind == LinkerOutputKind.STATIC_LIBRARY &&
config.isFinalBinary
val enabled = config.cacheSupport.preLinkCaches
val nonEmptyCaches = caches.static.isNotEmpty()
return isStaticLibrary && enabled && nonEmptyCaches
}
/**
* List of cache binaries that are required for the final artifact.
* [static] is a list of static libraries (e.g. "libcache.a")
* [dynamic] is a list of dynamic libraries (e.g. "libcache.dylib")
*/
internal class ResolvedCacheBinaries(val static: List<String>, val dynamic: List<String>)
/**
* Find binary files for compiler caches that are actually required for the linkage.
*/
internal fun resolveCacheBinaries(
cachedLibraries: CachedLibraries,
dependenciesTrackingResult: DependenciesTrackingResult,
): ResolvedCacheBinaries {
val staticCaches = mutableListOf<String>()
val dynamicCaches = mutableListOf<String>()
dependenciesTrackingResult.allCachedBitcodeDependencies.forEach { dependency ->
val library = dependency.library
val cache = cachedLibraries.getLibraryCache(library)
// Maybe turn it into a warning and continue linkage without caches?
?: error("Library $library is expected to be cached")
val list = when (cache.kind) {
CachedLibraries.Kind.DYNAMIC -> dynamicCaches
CachedLibraries.Kind.STATIC -> staticCaches
}
list += if (dependency.kind is DependenciesTracker.DependencyKind.CertainFiles && cache is CachedLibraries.Cache.PerFile)
dependency.kind.files.map { cache.getFileBinaryPath(it) }
else cache.binariesPaths
}
return ResolvedCacheBinaries(static = staticCaches, dynamic = dynamicCaches)
}
@@ -1,9 +1,6 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.konan.driver.PhaseContext import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
import org.jetbrains.kotlin.backend.konan.serialization.EagerInitializedPropertySerializer
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
import org.jetbrains.kotlin.konan.KonanExternalToolFailure import org.jetbrains.kotlin.konan.KonanExternalToolFailure
import org.jetbrains.kotlin.konan.TempFiles import org.jetbrains.kotlin.konan.TempFiles
import org.jetbrains.kotlin.konan.exec.Command import org.jetbrains.kotlin.konan.exec.Command
@@ -166,33 +163,24 @@ internal class Linker(
return executable return executable
} }
private fun shouldPerformPreLink(caches: CachesToLink, linkerOutputKind: LinkerOutputKind): Boolean {
// Pre-link is only useful when producing static library. Otherwise its just a waste of time.
val isStaticLibrary = linkerOutputKind == LinkerOutputKind.STATIC_LIBRARY &&
config.isFinalBinary
val enabled = config.cacheSupport.preLinkCaches
val nonEmptyCaches = caches.static.isNotEmpty()
return isStaticLibrary && enabled && nonEmptyCaches
}
private fun determineLinkerInput( private fun determineLinkerInput(
objectFiles: List<ObjectFile>, objectFiles: List<ObjectFile>,
linkerOutputKind: LinkerOutputKind, linkerOutputKind: LinkerOutputKind,
dependenciesTrackingResult: DependenciesTrackingResult, dependenciesTrackingResult: DependenciesTrackingResult,
): LinkerInput { ): LinkerInput {
val caches = determineCachesToLink(context, dependenciesTrackingResult) val caches = resolveCacheBinaries(context.config.cachedLibraries, dependenciesTrackingResult)
// Since we have several linker stages that involve caching, // Since we have several linker stages that involve caching,
// we should detect cache usage early to report errors correctly. // we should detect cache usage early to report errors correctly.
val cachingInvolved = caches.static.isNotEmpty() || caches.dynamic.isNotEmpty() val cachingInvolved = caches.static.isNotEmpty() || caches.dynamic.isNotEmpty()
return when { return when {
config.produce == CompilerOutputKind.STATIC_CACHE -> { config.produce == CompilerOutputKind.STATIC_CACHE -> {
// Do not link static cache dependencies. // Do not link static cache dependencies.
LinkerInput(objectFiles, CachesToLink(emptyList(), caches.dynamic), emptyList(), cachingInvolved) LinkerInput(objectFiles, ResolvedCacheBinaries(emptyList(), caches.dynamic), emptyList(), cachingInvolved)
} }
shouldPerformPreLink(caches, linkerOutputKind) -> { shouldPerformPreLink(config, caches, linkerOutputKind) -> {
val preLinkResult = tempFiles.create("withStaticCaches", ".o").absolutePath val preLinkResult = tempFiles.create("withStaticCaches", ".o").absolutePath
val preLinkCommands = linker.preLinkCommands(objectFiles + caches.static, preLinkResult) val preLinkCommands = linker.preLinkCommands(objectFiles + caches.static, preLinkResult)
LinkerInput(listOf(preLinkResult), CachesToLink(emptyList(), caches.dynamic), preLinkCommands, cachingInvolved) LinkerInput(listOf(preLinkResult), ResolvedCacheBinaries(emptyList(), caches.dynamic), preLinkCommands, cachingInvolved)
} }
else -> LinkerInput(objectFiles, caches, emptyList(), cachingInvolved) else -> LinkerInput(objectFiles, caches, emptyList(), cachingInvolved)
} }
@@ -201,33 +189,7 @@ internal class Linker(
private class LinkerInput( private class LinkerInput(
val objectFiles: List<ObjectFile>, val objectFiles: List<ObjectFile>,
val caches: CachesToLink, val caches: ResolvedCacheBinaries,
val preLinkCommands: List<Command>, val preLinkCommands: List<Command>,
val cachingInvolved: Boolean val cachingInvolved: Boolean
) )
private class CachesToLink(val static: List<String>, val dynamic: List<String>)
private fun determineCachesToLink(
context: PhaseContext,
dependenciesTrackingResult: DependenciesTrackingResult,
): CachesToLink {
val staticCaches = mutableListOf<String>()
val dynamicCaches = mutableListOf<String>()
dependenciesTrackingResult.allCachedBitcodeDependencies.forEach { dependency ->
val library = dependency.library
val cache = context.config.cachedLibraries.getLibraryCache(library)
?: error("Library $library is expected to be cached")
val list = when (cache.kind) {
CachedLibraries.Kind.DYNAMIC -> dynamicCaches
CachedLibraries.Kind.STATIC -> staticCaches
}
list += if (dependency.kind is DependenciesTracker.DependencyKind.CertainFiles && cache is CachedLibraries.Cache.PerFile)
dependency.kind.files.map { cache.getFileBinaryPath(it) }
else cache.binariesPaths
}
return CachesToLink(static = staticCaches, dynamic = dynamicCaches)
}