[Commonizer] Don't keep references to descriptor objects when they are not needed anymore

This is necessary to reduce overall memory consumption.
This commit is contained in:
Dmitriy Dolovov
2020-02-15 22:24:55 +07:00
parent 9a8a1113db
commit 667e96f971
24 changed files with 469 additions and 281 deletions
@@ -1,42 +0,0 @@
/*
* Copyright 2010-2019 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.descriptors.commonizer
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
class CommonizationParameters(
val statsCollector: StatsCollector? = null
) {
// use linked hash map to preserve order
private val modulesByTargets = LinkedHashMap<InputTarget, Collection<ModuleDescriptor>>()
fun addTarget(target: InputTarget, modules: Collection<ModuleDescriptor>): CommonizationParameters {
require(target !in modulesByTargets) { "Target $target is already added" }
val modulesWithUniqueNames = modules.groupingBy { it.name }.eachCount()
require(modulesWithUniqueNames.size == modules.size) {
"Modules with duplicated names found: ${modulesWithUniqueNames.filter { it.value > 1 }}"
}
modulesByTargets[target] = modules
return this
}
// get them as ordered immutable collection (List) for further processing
fun getModulesByTargets(): List<Pair<InputTarget, Collection<ModuleDescriptor>>> =
modulesByTargets.map { it.key to it.value }
fun hasIntersection(): Boolean {
if (modulesByTargets.size < 2)
return false
return modulesByTargets.flatMap { it.value }
.groupingBy { it.name }
.eachCount()
.any { it.value == modulesByTargets.size }
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2019 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.descriptors.commonizer
class Parameters(
val statsCollector: StatsCollector? = null
) {
// use linked hash map to preserve order
private val _targetProviders = LinkedHashMap<InputTarget, TargetProvider>()
val targetProviders: List<TargetProvider> get() = _targetProviders.values.toList()
fun addTarget(targetProvider: TargetProvider): Parameters {
require(targetProvider.target !in _targetProviders) { "Target ${targetProvider.target} is already added" }
_targetProviders[targetProvider.target] = targetProvider
return this
}
fun hasAnythingToCommonize(): Boolean = _targetProviders.size >= 2
}
@@ -7,13 +7,13 @@ package org.jetbrains.kotlin.descriptors.commonizer
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
sealed class CommonizationResult
sealed class Result
object NothingToCommonize : CommonizationResult()
object NothingToCommonize : Result()
class CommonizationPerformed(
val modulesByTargets: Map<Target, Collection<ModuleDescriptor>>
) : CommonizationResult() {
) : Result() {
val commonTarget: OutputTarget by lazy {
modulesByTargets.keys.filterIsInstance<OutputTarget>().single()
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2020 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.descriptors.commonizer
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
class TargetProvider(
val target: InputTarget,
val builtInsClass: Class<out KotlinBuiltIns>,
val builtInsProvider: BuiltInsProvider,
val modulesProvider: ModulesProvider
)
interface BuiltInsProvider {
fun loadBuiltIns(): KotlinBuiltIns
companion object {
fun wrap(builtIns: KotlinBuiltIns) = object : BuiltInsProvider {
override fun loadBuiltIns() = builtIns
}
}
}
interface ModulesProvider {
fun loadModules(): Collection<ModuleDescriptor>
companion object {
fun wrap(modules: Collection<ModuleDescriptor>) = object : ModulesProvider {
override fun loadModules() = modules
}
fun wrap(vararg modules: ModuleDescriptor) = wrap(modules.toList())
}
}
@@ -29,7 +29,7 @@ internal class DeclarationsBuilderVisitor1(
check(data.isEmpty()) // root node may not have containing declarations
check(components.targetComponents.size == node.dimension)
val allTargets = (node.target + node.common()!!).map { it.target }
val allTargets = (node.target + node.common()!!).map { it!!.target }
val modulesByTargets = HashMap<Target, MutableList<ModuleDescriptorImpl>>()
@@ -154,16 +154,16 @@ fun CirRootNode.createGlobalBuilderComponents(
val targetContexts = (0 until dimension).map { index ->
val isCommon = index == indexOfCommon
val target = (if (isCommon) common()!! else target[index]).target
val root = if (isCommon) common()!! else target[index]!!
val builtIns = modules.asSequence()
.mapNotNull { if (isCommon) it.common() else it.target[index] }
.first()
.builtIns
val builtIns = root.builtInsProvider.loadBuiltIns()
check(builtIns::class.java.name == root.builtInsClass) {
"Unexpected built-ins class: ${builtIns::class.java}, $builtIns\nExpected: ${root.builtInsClass}"
}
TargetDeclarationsBuilderComponents(
storageManager = storageManager,
target = target,
target = root.target,
builtIns = builtIns,
isCommon = isCommon,
index = index,
@@ -33,7 +33,7 @@ private fun CirModule.buildDescriptor(
val moduleDescriptor = ModuleDescriptorImpl(
moduleName = name,
storageManager = components.storageManager,
builtIns = builtIns,
builtIns = components.targetComponents[index].builtIns,
capabilities = emptyMap() // TODO: preserve capabilities from the original module descriptors, KT-33998
)
@@ -5,8 +5,6 @@
package org.jetbrains.kotlin.descriptors.commonizer.core
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirModule
import org.jetbrains.kotlin.name.Name
@@ -18,28 +16,12 @@ interface ModuleCommonizer : Commonizer<CirModule, CirModule> {
private class DefaultModuleCommonizer : ModuleCommonizer, AbstractStandardCommonizer<CirModule, CirModule>() {
private lateinit var name: Name
private var konanBuiltIns: KonanBuiltIns? = null
override fun commonizationResult() = CirModule(
name = name,
builtIns = konanBuiltIns ?: DefaultBuiltIns.Instance
)
override fun commonizationResult() = CirModule(name = name)
override fun initialize(first: CirModule) {
name = first.name
konanBuiltIns = first.konanBuiltIns
}
override fun doCommonizeWith(next: CirModule): Boolean {
// keep the first met KonanBuiltIns when all targets are Kotlin/Native
// otherwise use DefaultBuiltIns
if (konanBuiltIns != null) {
konanBuiltIns = konanBuiltIns.takeIf { next.konanBuiltIns != null }
}
return true
}
private inline val CirModule.konanBuiltIns
get() = builtIns as? KonanBuiltIns
override fun doCommonizeWith(next: CirModule) = true
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2020 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.descriptors.commonizer.core
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.commonizer.BuiltInsProvider
import org.jetbrains.kotlin.descriptors.commonizer.InputTarget
import org.jetbrains.kotlin.descriptors.commonizer.OutputTarget
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirRoot
interface RootCommonizer : Commonizer<CirRoot, CirRoot> {
companion object {
fun default(): RootCommonizer = DefaultRootCommonizer()
}
}
private class DefaultRootCommonizer : RootCommonizer, AbstractStandardCommonizer<CirRoot, CirRoot>() {
private val inputTargets = mutableSetOf<InputTarget>()
private var konanBuiltInsProvider: BuiltInsProvider? = null
override fun commonizationResult() = CirRoot(
target = OutputTarget(inputTargets),
builtInsClass = if (konanBuiltInsProvider != null) KonanBuiltIns::class.java.name else DefaultBuiltIns::class.java.name,
builtInsProvider = konanBuiltInsProvider ?: BuiltInsProvider.wrap(DefaultBuiltIns.Instance)
)
override fun initialize(first: CirRoot) {
inputTargets += first.target as InputTarget
konanBuiltInsProvider = first.konanBuiltInsProvider
}
override fun doCommonizeWith(next: CirRoot): Boolean {
inputTargets += next.target as InputTarget
// keep the first met KonanBuiltIns when all targets are Kotlin/Native
// otherwise use DefaultBuiltIns
if (konanBuiltInsProvider != null && next.konanBuiltInsProvider == null) {
konanBuiltInsProvider = null
}
return true
}
private inline val CirRoot.konanBuiltInsProvider
get() = if (builtInsClass == KonanBuiltIns::class.java.name) builtInsProvider else null
}
@@ -13,14 +13,14 @@ import org.jetbrains.kotlin.descriptors.commonizer.core.CommonizationVisitor
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.mergeRoots
import org.jetbrains.kotlin.storage.LockBasedStorageManager
fun runCommonization(parameters: CommonizationParameters): CommonizationResult {
if (!parameters.hasIntersection())
fun runCommonization(parameters: Parameters): Result {
if (!parameters.hasAnythingToCommonize())
return NothingToCommonize
val storageManager = LockBasedStorageManager("Declaration descriptors commonization")
// build merged tree:
val mergedTree = mergeRoots(storageManager, parameters.getModulesByTargets())
val mergedTree = mergeRoots(storageManager, parameters.targetProviders)
// commonize:
mergedTree.accept(CommonizationVisitor(mergedTree), Unit)
@@ -8,14 +8,11 @@ package org.jetbrains.kotlin.descriptors.commonizer.konan
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.backend.common.serialization.metadata.metadataVersion
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.commonizer.*
import org.jetbrains.kotlin.descriptors.commonizer.Target
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeModuleForCommonization.DeserializedModule
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeModuleForCommonization.SyntheticModule
import org.jetbrains.kotlin.descriptors.commonizer.utils.NativeFactories.DefaultDeserializedDescriptorFactory
import org.jetbrains.kotlin.descriptors.commonizer.utils.ResettableClockMark
import org.jetbrains.kotlin.descriptors.commonizer.utils.createKotlinNativeForwardDeclarationsModule
import org.jetbrains.kotlin.konan.library.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.library.KotlinLibrary
@@ -44,16 +41,16 @@ class NativeDistributionCommonizer(
checkPreconditions()
with(ResettableClockMark()) {
// 1. load modules
val modulesByTargets = loadModules()
// 1. load libraries
val librariesByTargets = loadLibraries()
logger.log("* Loaded lazy (uninitialized) libraries in ${elapsedSinceLast()}")
// 2. run commonization
val result = commonize(modulesByTargets)
val result = commonize(librariesByTargets)
logger.log("* Commonization performed in ${elapsedSinceLast()}")
// 3. write new libraries
saveModules(modulesByTargets, result)
saveModules(librariesByTargets, result)
logger.log("* Written libraries in ${elapsedSinceLast()}")
logger.log("TOTAL: ${elapsedSinceStart()}")
@@ -76,11 +73,11 @@ class NativeDistributionCommonizer(
}
}
private fun loadModules(): Map<InputTarget, List<NativeModuleForCommonization>> {
private fun loadLibraries(): Map<InputTarget, NativeDistributionLibraries> {
val stdlibPath = repository.resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME))
val stdlib = loadLibrary(stdlibPath)
val librariesByTargets = targets.map { target ->
return targets.associate { target ->
val platformLibsPath = repository.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR)
.resolve(target.name)
@@ -91,49 +88,7 @@ class NativeDistributionCommonizer(
?.map { loadLibrary(it) }
?: logger.fatal("no platform libraries found for target $target in $platformLibsPath")
InputTarget(target.name, target) to platformLibs
}.toMap()
return librariesByTargets.mapValues { (target, libraries) ->
val storageManager = LockBasedStorageManager("Target $target")
val rawStdlibModule = DefaultDeserializedDescriptorFactory.createDescriptorAndNewBuiltIns(
library = stdlib,
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
storageManager = storageManager,
packageAccessHandler = null
)
val otherModules = libraries.map { library ->
val rawModule = DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
library = library,
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
storageManager = storageManager,
builtIns = rawStdlibModule.builtIns,
packageAccessHandler = null
)
val data = NativeSensitiveManifestData.readFrom(library)
DeserializedModule(rawModule, data, File(library.libraryFile.path))
}
val rawForwardDeclarationsModule =
createKotlinNativeForwardDeclarationsModule(
storageManager = storageManager,
builtIns = rawStdlibModule.builtIns
)
val onlyDeserializedModules = listOf(rawStdlibModule) + otherModules.map { it.module }
val allModules = onlyDeserializedModules + rawForwardDeclarationsModule
onlyDeserializedModules.forEach { it.setDependencies(allModules) }
val stdlibModule = DeserializedModule(
rawStdlibModule,
NativeSensitiveManifestData.readFrom(stdlib),
File(stdlib.libraryFile.path)
)
val forwardDeclarationsModule = SyntheticModule(rawForwardDeclarationsModule)
listOf(stdlibModule) + otherModules + forwardDeclarationsModule
InputTarget(target.name, target) to NativeDistributionLibraries(stdlib, platformLibs)
}
}
@@ -162,25 +117,36 @@ class NativeDistributionCommonizer(
return library
}
private fun commonize(modulesByTargets: Map<InputTarget, List<NativeModuleForCommonization>>): CommonizationPerformed {
private fun commonize(librariesByTargets: Map<InputTarget, NativeDistributionLibraries>): CommonizationPerformed {
val statsCollector = if (withStats) NativeStatsCollector(targets, destination) else null
statsCollector.use {
val parameters = CommonizationParameters(statsCollector).apply {
modulesByTargets.forEach { (target, modules) ->
addTarget(target, modules.map { it.module })
val parameters = Parameters(statsCollector).apply {
librariesByTargets.forEach { (target, libraries) ->
val provider = NativeDistributionModulesProvider(
storageManager = LockBasedStorageManager("Target $target"),
libraries = libraries
)
addTarget(
TargetProvider(
target = target,
builtInsClass = KonanBuiltIns::class.java,
builtInsProvider = provider,
modulesProvider = provider
)
)
}
}
val result = runCommonization(parameters)
return when (result) {
is NothingToCommonize -> logger.fatal("too few targets specified: ${modulesByTargets.keys}")
is NothingToCommonize -> logger.fatal("too few targets specified: ${librariesByTargets.keys}")
is CommonizationPerformed -> result
}
}
}
private fun saveModules(
originalModulesByTargets: Map<InputTarget, List<NativeModuleForCommonization>>,
originalLibrariesByTargets: Map<InputTarget, NativeDistributionLibraries>,
result: CommonizationPerformed
) {
// optimization: stdlib and endorsed libraries effectively remain the same across all Kotlin/Native targets,
@@ -201,13 +167,6 @@ class NativeDistributionCommonizer(
}
}
val originalModulesManifestData = originalModulesByTargets.mapValues { (_, modules) ->
modules.asSequence()
.filterIsInstance<DeserializedModule>()
.filter { !it.location.endsWith(KONAN_STDLIB_NAME) }
.associate { it.module.name to it.data }
}
val serializer = KlibMetadataMonolithicSerializer(
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
metadataVersion = KlibMetadataVersion.INSTANCE,
@@ -216,16 +175,16 @@ class NativeDistributionCommonizer(
fun serializeTarget(target: Target) {
val libsDestination: File
val newModulesManifestData: Map<Name, NativeSensitiveManifestData>
val originalLibraries: NativeDistributionLibraries
when (target) {
is InputTarget -> {
libsDestination = destination.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(target.konanTarget!!.name)
newModulesManifestData = originalModulesManifestData.getValue(target)
originalLibraries = originalLibrariesByTargets.getValue(target)
}
is OutputTarget -> {
libsDestination = destination.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
newModulesManifestData = originalModulesManifestData.values.first() // just take the first one
originalLibraries = originalLibrariesByTargets.values.first() // just take the first one
}
}
@@ -238,8 +197,10 @@ class NativeDistributionCommonizer(
continue
val metadata = serializer.serializeModule(newModule)
val manifestData = newModulesManifestData.getValue(newModule.name)
val libraryDestination = libsDestination.resolve(libraryName.asString().trimStart('<').trimEnd('>'))
val plainName = libraryName.asString().removePrefix("<").removeSuffix(">")
val manifestData = originalLibraries.index.getValue(plainName).manifestData
val libraryDestination = libsDestination.resolve(plainName)
writeLibrary(metadata, manifestData, libraryDestination)
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2020 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.descriptors.commonizer.konan
import org.jetbrains.kotlin.library.KotlinLibrary
internal class NativeDistributionLibrary(
val library: KotlinLibrary
) {
val manifestData = NativeSensitiveManifestData.readFrom(library)
}
internal class NativeDistributionLibraries(
val stdlib: NativeDistributionLibrary,
val platformLibs: List<NativeDistributionLibrary>
) {
constructor(stdlib: KotlinLibrary, platformLibs: List<KotlinLibrary>) : this(
NativeDistributionLibrary(stdlib),
platformLibs.map(::NativeDistributionLibrary)
)
val index: Map<String, NativeDistributionLibrary> = (platformLibs + stdlib).associateBy { it.manifestData.uniqueName }
}
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2020 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.descriptors.commonizer.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.BuiltInsProvider
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider
import org.jetbrains.kotlin.descriptors.commonizer.utils.NativeFactories.DefaultDeserializedDescriptorFactory
import org.jetbrains.kotlin.descriptors.commonizer.utils.createKotlinNativeForwardDeclarationsModule
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
import org.jetbrains.kotlin.storage.StorageManager
internal class NativeDistributionModulesProvider(
private val storageManager: StorageManager,
private val libraries: NativeDistributionLibraries
) : BuiltInsProvider, ModulesProvider {
override fun loadBuiltIns(): KotlinBuiltIns {
val stdlib = DefaultDeserializedDescriptorFactory.createDescriptorAndNewBuiltIns(
library = libraries.stdlib.library,
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
storageManager = storageManager,
packageAccessHandler = null
)
stdlib.setDependencies(listOf(stdlib))
return stdlib.builtIns
}
override fun loadModules(): Collection<ModuleDescriptor> {
val builtIns = loadBuiltIns()
val stdlib = builtIns.builtInsModule
val platformModulesMap = libraries.platformLibs.associate { library ->
val name = library.manifestData.uniqueName
val module = DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
library = library.library,
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
storageManager = storageManager,
builtIns = builtIns,
packageAccessHandler = null
)
name to module
}
val forwardDeclarations = createKotlinNativeForwardDeclarationsModule(
storageManager = storageManager,
builtIns = builtIns
)
platformModulesMap.forEach { (name, module) ->
val dependencies = libraries.index
.getValue(name)
.manifestData
.dependencies
.map { if (it == KONAN_STDLIB_NAME) stdlib else platformModulesMap.getValue(it) }
module.setDependencies(listOf(module) + dependencies + forwardDeclarations)
}
return platformModulesMap.values
}
}
@@ -1,19 +0,0 @@
/*
* Copyright 2010-2019 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.descriptors.commonizer.konan
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import java.io.File
internal sealed class NativeModuleForCommonization(val module: ModuleDescriptorImpl) {
class DeserializedModule(
module: ModuleDescriptorImpl,
val data: NativeSensitiveManifestData,
val location: File
) : NativeModuleForCommonization(module)
class SyntheticModule(module: ModuleDescriptorImpl) : NativeModuleForCommonization(module)
}
@@ -5,10 +5,9 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.name.Name
data class CirModule(val name: Name, val builtIns: KotlinBuiltIns) : CirDeclaration {
constructor(descriptor: ModuleDescriptor) : this(descriptor.name, descriptor.builtIns) // TODO: strong ref
data class CirModule(val name: Name) : CirDeclaration {
constructor(descriptor: ModuleDescriptor) : this(descriptor.name)
}
@@ -5,6 +5,19 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.commonizer.BuiltInsProvider
import org.jetbrains.kotlin.descriptors.commonizer.InputTarget
import org.jetbrains.kotlin.descriptors.commonizer.Target
data class CirRoot(val target: Target) : CirDeclaration
data class CirRoot(
val target: Target,
val builtInsClass: String,
val builtInsProvider: BuiltInsProvider
) : CirDeclaration {
init {
if (target is InputTarget) {
check((target.konanTarget != null) == (builtInsClass == KonanBuiltIns::class.java.name))
}
}
}
@@ -6,8 +6,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.InputTarget
import org.jetbrains.kotlin.descriptors.commonizer.OutputTarget
import org.jetbrains.kotlin.descriptors.commonizer.TargetProvider
import org.jetbrains.kotlin.descriptors.commonizer.core.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirRootNode.ClassifiersCacheImpl
import org.jetbrains.kotlin.descriptors.commonizer.utils.CommonizedGroup
@@ -21,12 +20,14 @@ import org.jetbrains.kotlin.storage.StorageManager
internal fun buildRootNode(
storageManager: StorageManager,
targets: List<InputTarget>
): CirRootNode = CirRootNode(
target = targets.map { CirRoot(it) },
common = storageManager.createNullableLazyValue {
CirRoot(OutputTarget(targets.toSet()))
}
targetProviders: List<TargetProvider>
): CirRootNode = buildNode(
storageManager = storageManager,
descriptors = targetProviders,
targetDeclarationProducer = { CirRoot(it.target, it.builtInsClass.name, it.builtInsProvider) },
commonValueProducer = { commonize(it, RootCommonizer.default()) },
recursionMarker = null,
nodeProducer = ::CirRootNode
)
internal fun buildModuleNode(
@@ -21,7 +21,7 @@ interface CirNodeWithFqName<T : CirDeclaration, R : CirDeclaration> : CirNode<T,
}
class CirRootNode(
override val target: List<CirRoot>,
override val target: List<CirRoot?>,
override val common: NullableLazyValue<CirRoot>
) : CirNode<CirRoot, CirRoot> {
class ClassifiersCacheImpl : CirClassifiersCache {
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.InputTarget
import org.jetbrains.kotlin.descriptors.commonizer.TargetProvider
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirRootNode
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.buildRootNode
import org.jetbrains.kotlin.descriptors.commonizer.utils.CommonizedGroupMap
@@ -15,14 +15,14 @@ import org.jetbrains.kotlin.storage.StorageManager
internal fun mergeRoots(
storageManager: StorageManager,
modulesByTargets: List<Pair<InputTarget, Collection<ModuleDescriptor>>>
targetProviders: List<TargetProvider>
): CirRootNode {
val node = buildRootNode(storageManager, modulesByTargets.map { it.first })
val node = buildRootNode(storageManager, targetProviders)
val modulesMap = CommonizedGroupMap<Name, ModuleDescriptor>(modulesByTargets.size)
val modulesMap = CommonizedGroupMap<Name, ModuleDescriptor>(targetProviders.size)
modulesByTargets.forEachIndexed { index, (_, modules) ->
for (module in modules) {
targetProviders.forEachIndexed { index, targetProvider ->
for (module in targetProvider.modulesProvider.loadModules()) {
modulesMap[module.name][index] = module
}
}
@@ -35,9 +35,16 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
InputTarget("target_$index") to moduleDescriptor
}.toMap().toCommonizationParameters()
fun Map<InputTarget, ModuleDescriptor>.toCommonizationParameters() = CommonizationParameters().also {
fun Map<InputTarget, ModuleDescriptor>.toCommonizationParameters() = Parameters().also {
forEach { (target, moduleDescriptor) ->
it.addTarget(target, listOf(moduleDescriptor))
it.addTarget(
TargetProvider(
target = target,
builtInsClass = moduleDescriptor.builtIns::class.java,
builtInsProvider = BuiltInsProvider.wrap(moduleDescriptor.builtIns),
modulesProvider = ModulesProvider.wrap(moduleDescriptor)
)
)
}
}
}
@@ -55,19 +55,6 @@ class CommonizerFacadeTest {
}
}
@Test
fun mismatchedModules() {
val modules = listOf(
mockEmptyModule("<foo>"),
mockEmptyModule("<foo>"),
mockEmptyModule("<bar>")
)
val result = runCommonization(modules.eachModuleAsTarget())
assertEquals(NothingToCommonize, result)
}
private fun assertSingleModuleForTarget(
@Suppress("SameParameterValue") expectedModuleName: String,
modules: Collection<ModuleDescriptor>
@@ -1,79 +0,0 @@
/*
* Copyright 2010-2019 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.descriptors.commonizer.core
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirModule
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.junit.Test
class DefaultModuleCommonizerTest : AbstractCommonizerTest<CirModule, CirModule>() {
@Test
fun allAreNative() = doTestSuccess(
KONAN_BUILT_INS.toMock(),
KONAN_BUILT_INS.toMock(),
KONAN_BUILT_INS.toMock(),
KONAN_BUILT_INS.toMock()
)
@Test
fun jvmAndNative1() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(),
JVM_BUILT_INS.toMock(),
KONAN_BUILT_INS.toMock(),
JVM_BUILT_INS.toMock()
)
@Test
fun jvmAndNative2() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(),
KONAN_BUILT_INS.toMock(),
JVM_BUILT_INS.toMock(),
KONAN_BUILT_INS.toMock()
)
@Test
fun noNative1() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(),
JVM_BUILT_INS.toMock(),
JVM_BUILT_INS.toMock(),
JVM_BUILT_INS.toMock()
)
@Test
fun noNative2() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(),
DEFAULT_BUILT_INS.toMock(),
DEFAULT_BUILT_INS.toMock(),
DEFAULT_BUILT_INS.toMock()
)
@Test
fun noNative3() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(),
JVM_BUILT_INS.toMock(),
DEFAULT_BUILT_INS.toMock(),
JVM_BUILT_INS.toMock()
)
override fun createCommonizer() = ModuleCommonizer.default()
override fun isEqual(a: CirModule?, b: CirModule?) =
(a === b) || (a != null && b != null && a.name == b.name && a.builtIns::class.java.name == b.builtIns::class.java.name)
private companion object {
inline val KONAN_BUILT_INS get() = KonanBuiltIns(LockBasedStorageManager.NO_LOCKS)
inline val JVM_BUILT_INS get() = JvmBuiltIns(LockBasedStorageManager.NO_LOCKS, JvmBuiltIns.Kind.FROM_CLASS_LOADER)
inline val DEFAULT_BUILT_INS get() = DefaultBuiltIns.Instance
fun KotlinBuiltIns.toMock() = CirModule(Name.identifier("fakeModule"), this)
}
}
@@ -0,0 +1,172 @@
/*
* Copyright 2010-2020 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.descriptors.commonizer.core
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.commonizer.BuiltInsProvider
import org.jetbrains.kotlin.descriptors.commonizer.InputTarget
import org.jetbrains.kotlin.descriptors.commonizer.OutputTarget
import org.jetbrains.kotlin.descriptors.commonizer.Target
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirRoot
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.junit.Test
class DefaultRootCommonizerTest : AbstractCommonizerTest<CirRoot, CirRoot>() {
@Test
fun allAreNative() = doTestSuccess(
KONAN_BUILT_INS.toMock(
OutputTarget(
setOf(
InputTarget("ios_x64", KonanTarget.IOS_X64),
InputTarget("ios_arm64", KonanTarget.IOS_ARM64),
InputTarget("ios_arm32", KonanTarget.IOS_ARM32)
)
)
),
KONAN_BUILT_INS.toMock(InputTarget("ios_x64", KonanTarget.IOS_X64)),
KONAN_BUILT_INS.toMock(InputTarget("ios_arm64", KonanTarget.IOS_ARM64)),
KONAN_BUILT_INS.toMock(InputTarget("ios_arm32", KonanTarget.IOS_ARM32))
)
@Test
fun jvmAndNative1() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(
OutputTarget(
setOf(
InputTarget("jvm1"),
InputTarget("ios_x64", KonanTarget.IOS_X64),
InputTarget("jvm2")
)
)
),
JVM_BUILT_INS.toMock(InputTarget("jvm1")),
KONAN_BUILT_INS.toMock(InputTarget("ios_x64", KonanTarget.IOS_X64)),
JVM_BUILT_INS.toMock(InputTarget("jvm2"))
)
@Test
fun jvmAndNative2() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(
OutputTarget(
setOf(
InputTarget("ios_x64", KonanTarget.IOS_X64),
InputTarget("jvm"),
InputTarget("ios_arm64", KonanTarget.IOS_ARM64)
)
)
),
KONAN_BUILT_INS.toMock(InputTarget("ios_x64", KonanTarget.IOS_X64)),
JVM_BUILT_INS.toMock(InputTarget("jvm")),
KONAN_BUILT_INS.toMock(InputTarget("ios_arm64", KonanTarget.IOS_ARM64))
)
@Test
fun noNative1() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(
OutputTarget(
setOf(
InputTarget("default1"),
InputTarget("default2"),
InputTarget("default3")
)
)
),
DEFAULT_BUILT_INS.toMock(InputTarget("default1")),
DEFAULT_BUILT_INS.toMock(InputTarget("default2")),
DEFAULT_BUILT_INS.toMock(InputTarget("default3"))
)
@Test
fun noNative2() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(
OutputTarget(
setOf(
InputTarget("jvm1"),
InputTarget("default"),
InputTarget("jvm2")
)
)
),
JVM_BUILT_INS.toMock(InputTarget("jvm1")),
DEFAULT_BUILT_INS.toMock(InputTarget("default")),
JVM_BUILT_INS.toMock(InputTarget("jvm2"))
)
@Test
fun noNative3() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(
OutputTarget(
setOf(
InputTarget("jvm1"),
InputTarget("jvm2"),
InputTarget("jvm3")
)
)
),
JVM_BUILT_INS.toMock(InputTarget("jvm1")),
JVM_BUILT_INS.toMock(InputTarget("jvm2")),
JVM_BUILT_INS.toMock(InputTarget("jvm3"))
)
@Test(expected = IllegalStateException::class)
fun misconfiguration1() = doTestSuccess(
KONAN_BUILT_INS.toMock(
OutputTarget(
setOf(
InputTarget("ios_x64", KonanTarget.IOS_X64),
InputTarget("ios_arm64", KonanTarget.IOS_ARM64),
InputTarget("ios_arm32", KonanTarget.IOS_ARM32)
)
)
),
KONAN_BUILT_INS.toMock(InputTarget("ios_x64")),
KONAN_BUILT_INS.toMock(InputTarget("ios_arm64", KonanTarget.IOS_ARM64)),
KONAN_BUILT_INS.toMock(InputTarget("ios_arm32", KonanTarget.IOS_ARM32))
)
@Test(expected = IllegalStateException::class)
fun misconfiguration2() = doTestSuccess(
DEFAULT_BUILT_INS.toMock(
OutputTarget(
setOf(
InputTarget("jvm1"),
InputTarget("jvm2"),
InputTarget("jvm3")
)
)
),
JVM_BUILT_INS.toMock(InputTarget("jvm1", KonanTarget.IOS_X64)),
JVM_BUILT_INS.toMock(InputTarget("jvm2")),
JVM_BUILT_INS.toMock(InputTarget("jvm3"))
)
override fun createCommonizer() = RootCommonizer.default()
override fun isEqual(a: CirRoot?, b: CirRoot?) =
(a === b)
|| (a != null && b != null
&& a.target == b.target
&& a.builtInsClass == b.builtInsClass
&& a.builtInsClass == a.builtInsProvider.loadBuiltIns()::class.java.name
&& a.builtInsProvider.loadBuiltIns()::class.java == b.builtInsProvider.loadBuiltIns()::class.java)
private companion object {
inline val KONAN_BUILT_INS get() = KonanBuiltIns(LockBasedStorageManager.NO_LOCKS)
inline val JVM_BUILT_INS get() = JvmBuiltIns(LockBasedStorageManager.NO_LOCKS, JvmBuiltIns.Kind.FROM_CLASS_LOADER)
inline val DEFAULT_BUILT_INS get() = DefaultBuiltIns.Instance
fun KotlinBuiltIns.toMock(target: Target) = CirRoot(
target,
this::class.java.name,
BuiltInsProvider.wrap(this)
)
}
}
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.descriptors.commonizer.utils
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.CommonizationPerformed
import org.jetbrains.kotlin.descriptors.commonizer.CommonizationResult
import org.jetbrains.kotlin.descriptors.commonizer.Result
import org.jetbrains.kotlin.test.util.DescriptorValidator.*
import org.jetbrains.kotlin.types.ErrorUtils
import java.io.File
@@ -22,7 +22,7 @@ fun assertIsDirectory(file: File) {
}
@ExperimentalContracts
fun assertCommonizationPerformed(result: CommonizationResult) {
fun assertCommonizationPerformed(result: Result) {
contract {
returns() implies (result is CommonizationPerformed)
}