Rewritten unneeded library purge machinery.

This commit is contained in:
Alexander Gorshenev
2017-10-17 17:12:56 +03:00
committed by alexander-gorshenev
parent 6382215b9d
commit bddada22e5
7 changed files with 56 additions and 46 deletions
@@ -49,7 +49,7 @@ internal fun produceOutput(context: Context) {
val output = context.config.outputName val output = context.config.outputName
val libraryName = context.config.moduleId val libraryName = context.config.moduleId
val neededLibraries val neededLibraries
= context.config.immediateLibraries.purgeUnneeded() = context.config.librariesWithDependencies
val abiVersion = context.config.currentAbiVersion val abiVersion = context.config.currentAbiVersion
val target = context.config.targetManager.target val target = context.config.targetManager.target
val nopack = config.getBoolean(KonanConfigKeys.NOPACK) val nopack = config.getBoolean(KonanConfigKeys.NOPACK)
@@ -80,8 +80,4 @@ internal fun produceOutput(context: Context) {
} }
} }
internal fun List<KonanLibraryReader>.purgeUnneeded(): List<KonanLibraryReader> {
return this.map {
if (!it.isNeededForLink && it.isDefaultLink) null else it
}.filterNotNull()
}
@@ -1297,7 +1297,7 @@ internal object EscapeAnalysis {
val isStdlib = context.config.configuration[KonanConfigKeys.NOSTDLIB] == true val isStdlib = context.config.configuration[KonanConfigKeys.NOSTDLIB] == true
val externalFunctionEAResults = mutableMapOf<String, FunctionEscapeAnalysisResult>() val externalFunctionEAResults = mutableMapOf<String, FunctionEscapeAnalysisResult>()
context.config.libraries.forEach { library -> context.config.librariesWithDependencies.forEach { library ->
val libraryEscapeAnalysis = library.escapeAnalysis val libraryEscapeAnalysis = library.escapeAnalysis
if (libraryEscapeAnalysis != null) { if (libraryEscapeAnalysis != null) {
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
@@ -1338,4 +1338,4 @@ internal object EscapeAnalysis {
} }
} }
} }
} }
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.backend.konan
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.konan.descriptors.createForwardDeclarationsModule import org.jetbrains.kotlin.backend.konan.descriptors.createForwardDeclarationsModule
import org.jetbrains.kotlin.backend.konan.library.* import org.jetbrains.kotlin.backend.konan.library.*
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl import org.jetbrains.kotlin.backend.konan.library.impl.*
import org.jetbrains.kotlin.backend.konan.util.profile import org.jetbrains.kotlin.backend.konan.util.profile
import org.jetbrains.kotlin.backend.konan.util.removeSuffixIfPresent import org.jetbrains.kotlin.backend.konan.util.removeSuffixIfPresent
import org.jetbrains.kotlin.backend.konan.util.suffixIfNot import org.jetbrains.kotlin.backend.konan.util.suffixIfNot
@@ -92,8 +92,13 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
} }
} }
val libraries: List<LibraryReaderImpl> by lazy { // Accessing this field before resolve is a bad idea.
// purgeUnneeded() only works correctly after we have
// completed resolve and successfully marked package files
// as needed or not needed.
val librariesWithDependencies: List<KonanLibraryReader> by lazy {
resolver.resolveLibrariesRecursive(immediateLibraries, targetManager.target, currentAbiVersion) resolver.resolveLibrariesRecursive(immediateLibraries, targetManager.target, currentAbiVersion)
immediateLibraries.purgeUnneeded().withResolvedDependencies()
} }
private val loadedDescriptors = loadLibMetadata() private val loadedDescriptors = loadLibMetadata()
@@ -109,6 +114,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
val allMetadata = mutableListOf<ModuleDescriptorImpl>() val allMetadata = mutableListOf<ModuleDescriptorImpl>()
val specifics = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!! val specifics = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!!
val libraries = immediateLibraries.withResolvedDependencies()
for (klib in libraries) { for (klib in libraries) {
profile("Loading ${klib.libraryName}") { profile("Loading ${klib.libraryName}") {
// MutableModuleContext needs ModuleDescriptorImpl, rather than ModuleDescriptor. // MutableModuleContext needs ModuleDescriptorImpl, rather than ModuleDescriptor.
@@ -235,7 +235,7 @@ internal class LinkStage(val context: Context) {
private val debug = config.get(KonanConfigKeys.DEBUG) ?: false private val debug = config.get(KonanConfigKeys.DEBUG) ?: false
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
private val emitted = context.bitcodeFileName private val emitted = context.bitcodeFileName
private val libraries = context.config.libraries.purgeUnneeded() private val libraries = context.config.librariesWithDependencies
private fun MutableList<String>.addNonEmpty(elements: List<String>) { private fun MutableList<String>.addNonEmpty(elements: List<String>) {
addAll(elements.filter { !it.isEmpty() }) addAll(elements.filter { !it.isEmpty() })
} }
@@ -26,10 +26,9 @@ interface KonanLibraryReader {
val bitcodePaths: List<String> val bitcodePaths: List<String>
val includedPaths: List<String> val includedPaths: List<String>
val linkerOpts: List<String> val linkerOpts: List<String>
val dependencies: List<String> val unresolvedDependencies: List<String>
val escapeAnalysis: ByteArray? val escapeAnalysis: ByteArray?
val isNeededForLink: Boolean get() = true val isNeededForLink: Boolean get() = true
val isDefaultLink: Boolean get() = false
val manifestProperties: Properties val manifestProperties: Properties
val moduleHeaderData: ByteArray val moduleHeaderData: ByteArray
fun packageMetadata(fqName: String): ByteArray fun packageMetadata(fqName: String): ByteArray
@@ -49,7 +49,7 @@ fun SearchPathResolver.resolveImmediateLibraries(libraryNames: List<String>,
removeDuplicates: Boolean = true): List<LibraryReaderImpl> { removeDuplicates: Boolean = true): List<LibraryReaderImpl> {
val defaultLibraries = defaultLinks(nostdlib = noStdLib, noDefaultLibs = noDefaultLibs).map { val defaultLibraries = defaultLinks(nostdlib = noStdLib, noDefaultLibs = noDefaultLibs).map {
LibraryReaderImpl(it, abiVersion, target, isDefaultLink = true) LibraryReaderImpl(it, abiVersion, target)
} }
val userProvidedLibraries = libraryNames val userProvidedLibraries = libraryNames
@@ -65,33 +65,40 @@ fun SearchPathResolver.resolveImmediateLibraries(libraryNames: List<String>,
fun SearchPathResolver.resolveLibrariesRecursive(immediateLibraries: List<LibraryReaderImpl>, fun SearchPathResolver.resolveLibrariesRecursive(immediateLibraries: List<LibraryReaderImpl>,
target: KonanTarget, target: KonanTarget,
abiVersion: Int): List<LibraryReaderImpl> { abiVersion: Int) {
val result = mutableMapOf<File, LibraryReaderImpl>() val cache = mutableMapOf<File, LibraryReaderImpl>()
result.putAll(immediateLibraries.map { it.libraryFile.absoluteFile to it }) cache.putAll(immediateLibraries.map { it.libraryFile.absoluteFile to it })
var newDependencies: Map<File, LibraryReaderImpl> = result var newDependencies = cache.values.toList()
do { do {
val defaultOverrides = mutableSetOf<File>() newDependencies = newDependencies.map { library: LibraryReaderImpl ->
newDependencies = newDependencies.values.asSequence() library.unresolvedDependencies
.flatMap { it.dependencies.asSequence() } .map { resolve(it).absoluteFile }
.map { resolve(it).absoluteFile } .map {
.onEach { if (it in cache) {
if (result[it]?.isDefaultLink == true) { library.resolvedDependencies.add(cache[it]!!)
defaultOverrides.add(it) null
} } else {
} val reader = LibraryReaderImpl(it, abiVersion, target)
.filter { it !in result } cache.put(it,reader)
.map { it to LibraryReaderImpl(it, abiVersion, target) }.toMap() library.resolvedDependencies.add(reader)
reader
result.putAll(newDependencies) }
}.filterNotNull()
// If there is a default link in immediateLibraries, } .flatten()
// and we get the same library as a dependency,
// the resultant surviving library should not be a defaultLink anymore.
defaultOverrides.forEach {
result[it] = LibraryReaderImpl(it, abiVersion, target)
}
} while (newDependencies.isNotEmpty()) } while (newDependencies.isNotEmpty())
return result.values.toList() }
fun List<LibraryReaderImpl>.withResolvedDependencies(): List<LibraryReaderImpl> {
val result = mutableSetOf<LibraryReaderImpl>()
result.addAll(this)
var newDependencies = result.toList()
do {
newDependencies = newDependencies
.map { it -> it.resolvedDependencies } .flatten()
.filter { it !in result }
result.addAll(newDependencies)
} while (newDependencies.isNotEmpty())
return result.toList()
} }
fun SearchPathResolver.resolveLibrariesRecursive(libraryNames: List<String>, fun SearchPathResolver.resolveLibrariesRecursive(libraryNames: List<String>,
@@ -99,17 +106,16 @@ fun SearchPathResolver.resolveLibrariesRecursive(libraryNames: List<String>,
abiVersion: Int = 1, abiVersion: Int = 1,
noStdLib: Boolean = false, noStdLib: Boolean = false,
noDefaultLibs: Boolean = false): List<LibraryReaderImpl> { noDefaultLibs: Boolean = false): List<LibraryReaderImpl> {
return resolveLibrariesRecursive( val immediateLibraries = resolveImmediateLibraries(
resolveImmediateLibraries(
libraryNames = libraryNames, libraryNames = libraryNames,
target = target, target = target,
abiVersion = abiVersion, abiVersion = abiVersion,
noStdLib = noStdLib, noStdLib = noStdLib,
noDefaultLibs = noDefaultLibs, noDefaultLibs = noDefaultLibs,
removeDuplicates = true removeDuplicates = true
), )
target, abiVersion resolveLibrariesRecursive(immediateLibraries, target, abiVersion)
) return immediateLibraries.withResolvedDependencies()
} }
class KonanLibrarySearchPathResolver( class KonanLibrarySearchPathResolver(
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int, class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int,
val target: KonanTarget? = null, override val isDefaultLink: Boolean = false) val target: KonanTarget? = null)
: KonanLibraryReader { : KonanLibraryReader {
// For the zipped libraries inPlace gives files from zip file system // For the zipped libraries inPlace gives files from zip file system
@@ -68,9 +68,11 @@ class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int,
override val linkerOpts: List<String> override val linkerOpts: List<String>
get() = manifestProperties.propertyList("linkerOpts", target!!.detailedName) get() = manifestProperties.propertyList("linkerOpts", target!!.detailedName)
override val dependencies: List<String> override val unresolvedDependencies: List<String>
get() = manifestProperties.propertyList("dependencies") get() = manifestProperties.propertyList("dependencies")
val resolvedDependencies = mutableListOf<LibraryReaderImpl>()
override val moduleHeaderData: ByteArray by lazy { override val moduleHeaderData: ByteArray by lazy {
reader.loadSerializedModule() reader.loadSerializedModule()
} }
@@ -96,3 +98,4 @@ class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int,
} }
internal fun <T: KonanLibraryReader> List<T>.purgeUnneeded(): List<T> = this.filter{ it.isNeededForLink }