[Commonizer] Implement CirTree and CirTree deserializers and CirTree merging

This commit is contained in:
sebastian.sellmair
2021-03-25 16:33:36 +01:00
parent cb1f3c3e32
commit 108debdcc9
20 changed files with 642 additions and 56 deletions
@@ -9,20 +9,20 @@ import org.jetbrains.kotlin.commonizer.konan.NativeManifestDataProvider
import org.jetbrains.kotlin.commonizer.stats.StatsCollector
class CommonizerParameters(
val targetProviders: List<TargetProvider>,
val targetProviders: TargetDependent<TargetProvider>,
val resultsConsumer: ResultsConsumer,
val commonManifestProvider: NativeManifestDataProvider,
val commonDependencyModulesProvider: ModulesProvider? = null,
val statsCollector: StatsCollector? = null,
val progressLogger: ((String) -> Unit)? = null
) {
internal val commonTarget: SharedCommonizerTarget = SharedCommonizerTarget(targetProviders.map { it.target }.toSet())
internal val commonTarget: SharedCommonizerTarget = SharedCommonizerTarget(targetProviders.targets.toSet())
internal val manifestDataProvider: TargetDependent<NativeManifestDataProvider>
get() = TargetDependent { target ->
get() = TargetDependent(setOf(SharedCommonizerTarget(targetProviders.targets.toSet())) + targetProviders.targets) { target ->
if (target == commonTarget) return@TargetDependent commonManifestProvider
this.targetProviders.firstOrNull { it.target == target }?.manifestProvider?.let { return@TargetDependent it }
null
throw IllegalStateException("Illegal target $target")
}
}
@@ -30,7 +30,7 @@ class CommonizerParameters(
fun CommonizerParameters.getCommonModuleNames(): Set<String> {
if (targetProviders.size < 2) return emptySet() // too few targets
val allModuleNames: List<Set<String>> = targetProviders.map { targetProvider ->
val allModuleNames: List<Set<String>> = targetProviders.toList().map { targetProvider ->
targetProvider.modulesProvider.loadModuleInfos().mapTo(HashSet()) { it.name }
}
@@ -7,43 +7,95 @@
package org.jetbrains.kotlin.commonizer
sealed interface TargetDependent<T : Any> {
fun getOrNull(target: CommonizerTarget): T?
operator fun get(target: CommonizerTarget): T {
return getOrNull(target) ?: throw NoSuchElementException("Missing element for target ${target.prettyName}")
sealed interface TargetDependent<T> : Iterable<T> {
val size: Int get() = targets.size
val targets: List<CommonizerTarget>
fun indexOf(target: CommonizerTarget): Int = targets.indexOf(target)
fun <R : Any> map(mapper: (target: CommonizerTarget, T) -> R): TargetDependent<R> {
return TargetDependent(targets) { target ->
mapper(target, get(target))
}
}
override fun iterator(): Iterator<T> {
return iterator { for (key in targets) yield(this@TargetDependent[key]) }
}
operator fun get(target: CommonizerTarget): T
fun getOrNull(target: CommonizerTarget): T? {
return if (target in targets) get(target) else null
}
}
internal fun <T : Any> Map<CommonizerTarget, T>.toTargetDependent(): TargetDependent<T> {
internal fun <T : Any> TargetDependent<T?>.filterNonNull(): TargetDependent<T> {
val nonNullTargets = targets.filter { this[it] != null }
return TargetDependent(nonNullTargets) { target -> this@filterNonNull[target] ?: throw NullPointerException() }
}
internal fun <T> TargetDependent<T>.toMap(): Map<CommonizerTarget, T> {
return mutableMapOf<CommonizerTarget, T>().apply {
for (key in keys) {
put(key, this@toMap[key])
}
}
}
internal fun <T> Map<out CommonizerTarget, T>.toTargetDependent(): TargetDependent<T> {
return TargetDependent(toMap())
}
internal fun <T : Any> Map<CommonizerTarget, T>.asTargetDependent(): TargetDependent<T> {
return TargetDependent(this)
internal fun <T, R> TargetDependent<T>.mapValue(mapper: (T) -> R): TargetDependent<R> {
return TargetDependent(targets) { target -> this@mapValue.get(target).let(mapper) }
}
internal fun <T : Any, R : Any> TargetDependent<T>.map(mapper: (T) -> R): TargetDependent<R> {
return TargetDependent { target -> this@map.getOrNull(target)?.let(mapper) }
internal fun <T, R> TargetDependent<T>.mapTargets(mapper: (CommonizerTarget) -> R): TargetDependent<R> {
return TargetDependent(targets) { target -> mapper(target) }
}
internal fun <T : Any> TargetDependent(map: Map<CommonizerTarget, T>): TargetDependent<T> {
internal fun <T> TargetDependent(map: Map<CommonizerTarget, T>): TargetDependent<T> {
return MapBasedTargetDependent(map)
}
internal fun <T : Any> TargetDependent(factory: (target: CommonizerTarget) -> T?): TargetDependent<T> {
return FactoryBasedTargetDependent(factory)
internal fun <T> TargetDependent(keys: Iterable<CommonizerTarget>, factory: (target: CommonizerTarget) -> T): TargetDependent<T> {
return FactoryBasedTargetDependent(keys.toList(), factory)
}
private class MapBasedTargetDependent<T : Any>(private val map: Map<CommonizerTarget, T>) : TargetDependent<T> {
override fun getOrNull(target: CommonizerTarget): T? = map[target]
private class MapBasedTargetDependent<T>(private val map: Map<CommonizerTarget, T>) : TargetDependent<T> {
override val targets: List<CommonizerTarget> = map.keys.toList()
override fun get(target: CommonizerTarget): T = map.getValue(target)
}
private class FactoryBasedTargetDependent<T : Any>(private val factory: (target: CommonizerTarget) -> T?) : TargetDependent<T> {
private val values = mutableMapOf<CommonizerTarget, Any>()
override fun getOrNull(target: CommonizerTarget): T? {
@Suppress("unchecked_cast")
return values.getOrPut(target) { factory(target) ?: Null }.takeIf { it != Null }?.run { this as T }
/**
* Not thread safe!
*/
private class FactoryBasedTargetDependent<T>(
override val targets: List<CommonizerTarget>,
private var factory: ((target: CommonizerTarget) -> T)?
) : TargetDependent<T> {
private object Uninitialized
private val values: Array<Any?> = Array(targets.size) { Uninitialized }
@Suppress("UNCHECKED_CAST")
override fun get(target: CommonizerTarget): T {
val indexOfTarget = indexOf(target)
if (indexOfTarget < 0) throw NoSuchElementException("Missing target $target")
val storedValue = values[indexOfTarget]
if (storedValue == Uninitialized) {
val producedValue = factory?.invoke(target)
values[indexOfTarget] = producedValue
/* All values initialized. Factory can be released */
if (values.none { it === Uninitialized }) {
factory = null
}
return producedValue as T
}
return storedValue as T
}
private object Null
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.commonizer.cir
import org.jetbrains.kotlin.commonizer.mergedtree.PropertyApproximationKey
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.commonizer.core.CommonizationVisitor
import org.jetbrains.kotlin.commonizer.mergedtree.*
import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.dimension
import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer
import org.jetbrains.kotlin.commonizer.tree.deserializer.deserialize
import org.jetbrains.kotlin.commonizer.tree.merger.mergeCirTree
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
@@ -24,18 +26,17 @@ fun runCommonization(parameters: CommonizerParameters) {
val storageManager = LockBasedStorageManager("Declarations commonization")
val mergeResult = mergeAndCommonize(storageManager, parameters)
val mergedTree = mergeResult.root
val mergedTree = mergeAndCommonize(storageManager, parameters)
// build resulting declarations:
for (targetIndex in 0 until mergedTree.dimension) {
serializeTarget(mergeResult, targetIndex, parameters)
serializeTarget(mergedTree, targetIndex, parameters)
}
parameters.resultsConsumer.allConsumed(Status.DONE)
}
private fun mergeAndCommonize(storageManager: StorageManager, parameters: CommonizerParameters): CirTreeMergeResult {
private fun mergeAndCommonize(storageManager: StorageManager, parameters: CommonizerParameters): CirRootNode {
// build merged tree:
val classifiers = CirKnownClassifiers(
commonizedNodes = CirCommonizedClassifierNodes.default(),
@@ -44,17 +45,18 @@ private fun mergeAndCommonize(storageManager: StorageManager, parameters: Common
CirProvidedClassifiers.by(parameters.commonDependencyModulesProvider)
)
)
val mergeResult = mergeCirTree(storageManager, classifiers, parameters)
// commonize:
mergeResult.root.accept(CommonizationVisitor(classifiers, mergeResult.root), Unit)
val targetTrees = parameters.targetProviders.mapValue { target -> deserialize(parameters, target) }
parameters.progressLogger?.invoke("Deserialized targets")
val mergedTree = mergeCirTree(storageManager, classifiers, targetTrees)
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
parameters.progressLogger?.invoke("Commonized declarations")
return mergeResult
return mergedTree
}
private fun serializeTarget(mergeResult: CirTreeMergeResult, targetIndex: Int, parameters: CommonizerParameters) {
val mergedTree = mergeResult.root
private fun serializeTarget(mergedTree: CirRootNode, targetIndex: Int, parameters: CommonizerParameters) {
val target = mergedTree.getTarget(targetIndex)
CirTreeSerializer.serializeSingleTarget(mergedTree, targetIndex, parameters.statsCollector) { metadataModule ->
@@ -66,10 +68,10 @@ private fun serializeTarget(mergeResult: CirTreeMergeResult, targetIndex: Int, p
parameters.resultsConsumer.consume(target, ModuleResult.Commonized(libraryName, serializedMetadata, manifestData))
}
if (target is LeafCommonizerTarget) {
mergeResult.missingModuleInfos.getValue(target).forEach {
parameters.resultsConsumer.consume(target, ModuleResult.Missing(it.originalLocation))
}
if (target in parameters.targetProviders.targets) {
parameters.targetProviders[target].modulesProvider.loadModuleInfos()
.filter { it.name !in parameters.getCommonModuleNames() }
.forEach { missingModule -> parameters.resultsConsumer.consume(target, ModuleResult.Missing(missingModule.originalLocation)) }
}
parameters.resultsConsumer.targetConsumed(target)
@@ -42,7 +42,8 @@ internal class LibraryCommonizer internal constructor(
private fun commonizeAndSaveResults(allLibraries: TargetDependent<NativeLibrariesToCommonize>) {
val parameters = CommonizerParameters(
targetProviders = commonTarget.targets.mapNotNull { target -> createTargetProvider(target, allLibraries[target]) },
targetProviders = TargetDependent(commonTarget.targets) { target -> createTargetProvider(target, allLibraries[target]) }
.filterNonNull(),
resultsConsumer = resultsConsumer,
commonManifestProvider = CommonNativeManifestDataProvider(commonTarget.targets.map { allLibraries[it] }),
commonDependencyModulesProvider = DefaultModulesProvider.create(dependencies.getLibraries(commonTarget)),
@@ -63,7 +63,11 @@ internal class ClassesToProcess {
}
}
fun classesInScope(parentClassId: CirEntityId?): List<ClassEntry> {
return groupedByParentClassId[parentClassId ?: NON_EXISTING_CLASSIFIER_ID].orEmpty()
}
fun forEachClassInScope(parentClassId: CirEntityId?, block: (ClassEntry) -> Unit) {
groupedByParentClassId[parentClassId ?: NON_EXISTING_CLASSIFIER_ID]?.forEach { classEntry -> block(classEntry) }
classesInScope(parentClassId).forEach { classEntry -> block(classEntry) }
}
}
@@ -10,6 +10,7 @@ import kotlinx.metadata.KmTypeParameter
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvided
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvidedClassifiers
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.ClassesToProcess
typealias TypeParameterId = Int
typealias TypeParameterIndex = Int
@@ -71,6 +72,13 @@ abstract class CirTypeResolver : CirTypeParameterResolver {
Nested(this, mapping)
}
internal fun create(classEntry: ClassesToProcess.ClassEntry): CirTypeResolver {
return when (classEntry) {
is ClassesToProcess.ClassEntry.RegularClassEntry -> create(classEntry.clazz.typeParameters)
is ClassesToProcess.ClassEntry.EnumEntry -> this
}
}
companion object {
fun create(providedClassifiers: CirProvidedClassifiers): CirTypeResolver = TopLevel(providedClassifiers)
}
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2021 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.commonizer.tree
import org.jetbrains.kotlin.commonizer.cir.*
import org.jetbrains.kotlin.commonizer.mergedtree.ConstructorApproximationKey
import org.jetbrains.kotlin.commonizer.mergedtree.FunctionApproximationKey
import org.jetbrains.kotlin.commonizer.mergedtree.PropertyApproximationKey
data class CirTreeRoot(
val modules: List<CirTreeModule>
)
data class CirTreeModule(
val module: CirModule,
val packages: List<CirTreePackage>
)
data class CirTreePackage(
val pkg: CirPackage,
val properties: List<CirTreeProperty>,
val functions: List<CirTreeFunction>,
val classes: List<CirTreeClass>,
val typeAliases: List<CirTreeTypeAlias>
)
data class CirTreeProperty(
val approximationKey: PropertyApproximationKey,
val property: CirProperty
)
data class CirTreeFunction(
val approximationKey: FunctionApproximationKey,
val function: CirFunction
)
data class CirTreeTypeAlias(
val id: CirEntityId,
val typeAlias: CirTypeAlias
)
data class CirTreeClass(
val id: CirEntityId,
val clazz: CirClass,
val properties: List<CirTreeProperty>,
val functions: List<CirTreeFunction>,
val constructors: List<CirTreeClassConstructor>,
val classes: List<CirTreeClass>,
)
class CirTreeClassConstructor(
val approximationKey: ConstructorApproximationKey,
val constructor: CirClassConstructor
)
@@ -0,0 +1,72 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import kotlinx.metadata.Flag
import kotlinx.metadata.KmClass
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.ClassesToProcess
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeClass
internal class ClassCirTreeDeserializer(
private val propertyDeserializer: PropertyCirTreeDeserializer,
private val functionDeserializer: FunctionCirTreeDeserializer,
private val constructorDeserializer: ClassConstructorCirTreeDeserializer,
) {
operator fun invoke(
classEntry: ClassesToProcess.ClassEntry, classesToProcess: ClassesToProcess, typeResolver: CirTypeResolver
): CirTreeClass {
val classTypeResolver = typeResolver.create(classEntry)
val classId = classEntry.classId
val className = classId.relativeNameSegments.last()
val clazz: KmClass?
val isEnumEntry: Boolean
val cirClass = when (classEntry) {
is ClassesToProcess.ClassEntry.RegularClassEntry -> {
clazz = classEntry.clazz
isEnumEntry = Flag.Class.IS_ENUM_ENTRY(clazz.flags)
CirDeserializers.clazz(className, clazz, classTypeResolver)
}
is ClassesToProcess.ClassEntry.EnumEntry -> {
clazz = null
isEnumEntry = true
CirDeserializers.defaultEnumEntry(
name = className,
annotations = classEntry.annotations,
enumClassId = classEntry.enumClassId,
enumClass = classEntry.enumClass,
typeResolver = classTypeResolver
)
}
}
val constructors = clazz?.constructors
?.takeIf { !isEnumEntry }
?.map { constructor -> constructorDeserializer(constructor, cirClass, classTypeResolver) }
.orEmpty()
val properties = clazz?.properties?.mapNotNull { property -> propertyDeserializer(property, cirClass, classTypeResolver) }
val functions = clazz?.functions?.mapNotNull { function -> functionDeserializer(function, cirClass, classTypeResolver) }
val classes = classesToProcess.classesInScope(classId).map { nestedClassEntry ->
this(nestedClassEntry, classesToProcess, classTypeResolver)
}
return CirTreeClass(
id = classId,
clazz = cirClass,
properties = properties.orEmpty(),
functions = functions.orEmpty(),
constructors = constructors,
classes = classes
)
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import kotlinx.metadata.KmConstructor
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
import org.jetbrains.kotlin.commonizer.mergedtree.ConstructorApproximationKey
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeClassConstructor
internal object ClassConstructorCirTreeDeserializer {
operator fun invoke(
constructor: KmConstructor, containingClass: CirContainingClass, typeResolver: CirTypeResolver
): CirTreeClassConstructor {
return CirTreeClassConstructor(
approximationKey = ConstructorApproximationKey(constructor, typeResolver),
constructor = CirDeserializers.constructor(
source = constructor,
containingClass = containingClass,
typeResolver = typeResolver
)
)
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import kotlinx.metadata.KmFunction
import org.jetbrains.kotlin.commonizer.cir.CirClass
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
import org.jetbrains.kotlin.commonizer.mergedtree.FunctionApproximationKey
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeFunction
import org.jetbrains.kotlin.commonizer.utils.isFakeOverride
import org.jetbrains.kotlin.commonizer.utils.isKniBridgeFunction
import org.jetbrains.kotlin.commonizer.utils.isTopLevelDeprecatedFunction
object FunctionCirTreeDeserializer {
operator fun invoke(function: KmFunction, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirTreeFunction? {
val functionTypeResolver = typeResolver.create(function.typeParameters)
if (function.isFakeOverride()
|| function.isKniBridgeFunction()
|| function.isTopLevelDeprecatedFunction(isTopLevel = containingClass !is CirClass)
) {
return null
}
val approximationKey = FunctionApproximationKey(function, functionTypeResolver)
return CirTreeFunction(
approximationKey = approximationKey,
function = CirDeserializers.function(
name = approximationKey.name,
source = function,
containingClass = containingClass,
typeResolver = functionTypeResolver
)
)
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import kotlinx.metadata.KmModuleFragment
import kotlinx.metadata.klib.KlibModuleMetadata
import kotlinx.metadata.klib.fqName
import org.jetbrains.kotlin.commonizer.cir.CirModule
import org.jetbrains.kotlin.commonizer.cir.CirName
import org.jetbrains.kotlin.commonizer.cir.CirPackageName
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.metadata.utils.SerializedMetadataLibraryProvider
import org.jetbrains.kotlin.commonizer.tree.CirTreeModule
import org.jetbrains.kotlin.commonizer.utils.foldToMap
import org.jetbrains.kotlin.library.SerializedMetadata
internal class ModuleCirTreeDeserializer(
private val packageDeserializer: PackageCirTreeDeserializer
) {
operator fun invoke(metadata: SerializedMetadata, typeResolver: CirTypeResolver): CirTreeModule {
val module = KlibModuleMetadata.read(SerializedMetadataLibraryProvider(metadata))
val fragmentsByPackage: Map<CirPackageName, Collection<KmModuleFragment>> = module.fragments.foldToMap { fragment ->
fragment.fqName?.let(CirPackageName.Companion::create)
?: error("A fragment without FQ name in module ${module.name}: $fragment")
}
val packages = fragmentsByPackage.map { (packageName, fragments) ->
packageDeserializer(packageName, fragments, typeResolver)
}
return CirTreeModule(
module = CirModule.create(CirName.create(module.name)),
packages = packages
)
}
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import kotlinx.metadata.KmModuleFragment
import org.jetbrains.kotlin.commonizer.cir.CirPackage
import org.jetbrains.kotlin.commonizer.cir.CirPackageName
import org.jetbrains.kotlin.commonizer.mergedtree.mergers.ClassesToProcess
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreePackage
internal class PackageCirTreeDeserializer(
private val propertyDeserializer: PropertyCirTreeDeserializer,
private val functionDeserializer: FunctionCirTreeDeserializer,
private val typeAliasDeserializer: TypeAliasCirTreeDeserializer,
private val classDeserializer: ClassCirTreeDeserializer,
) {
operator fun invoke(
packageName: CirPackageName,
fragments: Collection<KmModuleFragment>,
typeResolver: CirTypeResolver
): CirTreePackage {
val pkg = CirPackage.create(packageName)
val properties = fragments.asSequence().mapNotNull { it.pkg }
.flatMap { it.properties }
.mapNotNull { property -> propertyDeserializer(property, null, typeResolver) }
.toList()
val functions = fragments.asSequence().mapNotNull { it.pkg }
.flatMap { it.functions }
.mapNotNull { function -> functionDeserializer(function, null, typeResolver) }
.toList()
val typeAliases = fragments.asSequence().mapNotNull { it.pkg }
.flatMap { it.typeAliases }
.mapNotNull { typeAlias -> typeAliasDeserializer(typeAlias, pkg.packageName, typeResolver) }
.toList()
val classes = ClassesToProcess()
.apply { fragments.forEach { fragment -> addClassesFromFragment(fragment) } }
.run { classesInScope(parentClassId = null).map { classEntry -> classDeserializer(classEntry, this, typeResolver) } }
return CirTreePackage(
pkg = pkg,
properties = properties,
functions = functions,
typeAliases = typeAliases,
classes = classes
)
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import kotlinx.metadata.KmProperty
import org.jetbrains.kotlin.commonizer.cir.CirContainingClass
import org.jetbrains.kotlin.commonizer.mergedtree.PropertyApproximationKey
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeProperty
import org.jetbrains.kotlin.commonizer.utils.isFakeOverride
object PropertyCirTreeDeserializer {
operator fun invoke(property: KmProperty, containingClass: CirContainingClass?, typeResolver: CirTypeResolver): CirTreeProperty? {
if (property.isFakeOverride()) return null
val propertyTypeResolver = typeResolver.create(property.typeParameters)
val approximationKey = PropertyApproximationKey(property, propertyTypeResolver)
return CirTreeProperty(
approximationKey = PropertyApproximationKey(property, propertyTypeResolver),
property = CirDeserializers.property(
name = approximationKey.name,
source = property,
containingClass = containingClass,
typeResolver = propertyTypeResolver
)
)
}
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import org.jetbrains.kotlin.commonizer.CommonizerParameters
import org.jetbrains.kotlin.commonizer.TargetProvider
import org.jetbrains.kotlin.commonizer.getCommonModuleNames
import org.jetbrains.kotlin.commonizer.mergedtree.CirFictitiousFunctionClassifiers
import org.jetbrains.kotlin.commonizer.mergedtree.CirProvidedClassifiers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
internal class RootCirTreeDeserializer(
private val moduleDeserializer: ModuleCirTreeDeserializer
) {
operator fun invoke(parameters: CommonizerParameters, targetProvider: TargetProvider): CirTreeRoot {
val commonModuleInfos = targetProvider.modulesProvider.loadModuleInfos()
.filter { moduleInfo -> moduleInfo.name in parameters.getCommonModuleNames() }
val typeResolver = CirTypeResolver.create(
providedClassifiers = CirProvidedClassifiers.of(
CirProvidedClassifiers.by(targetProvider.modulesProvider),
CirProvidedClassifiers.by(targetProvider.dependencyModulesProvider),
CirProvidedClassifiers.of(
CirFictitiousFunctionClassifiers,
CirProvidedClassifiers.by(parameters.commonDependencyModulesProvider)
)
)
)
return CirTreeRoot(
modules = commonModuleInfos.map { moduleInfo ->
val metadata = targetProvider.modulesProvider.loadModuleMetadata(moduleInfo.name)
moduleDeserializer(metadata, typeResolver)
}
)
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import kotlinx.metadata.KmTypeAlias
import org.jetbrains.kotlin.commonizer.cir.CirEntityId
import org.jetbrains.kotlin.commonizer.cir.CirName
import org.jetbrains.kotlin.commonizer.cir.CirPackageName
import org.jetbrains.kotlin.commonizer.metadata.CirDeserializers
import org.jetbrains.kotlin.commonizer.metadata.CirTypeResolver
import org.jetbrains.kotlin.commonizer.tree.CirTreeTypeAlias
internal object TypeAliasCirTreeDeserializer {
operator fun invoke(typeAlias: KmTypeAlias, packageName: CirPackageName, typeResolver: CirTypeResolver): CirTreeTypeAlias {
val typeAliasTypeResolver = typeResolver.create(typeAlias.typeParameters)
val typeAliasName = CirName.create(typeAlias.name)
return CirTreeTypeAlias(
id = CirEntityId.create(packageName, typeAliasName),
typeAlias = CirDeserializers.typeAlias(
name = typeAliasName,
source = typeAlias,
typeResolver = typeAliasTypeResolver
)
)
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2021 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.commonizer.tree.deserializer
import org.jetbrains.kotlin.commonizer.CommonizerParameters
import org.jetbrains.kotlin.commonizer.TargetProvider
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
private val defaultRootCirTreeDeserializer = RootCirTreeDeserializer(
ModuleCirTreeDeserializer(
packageDeserializer = PackageCirTreeDeserializer(
propertyDeserializer = PropertyCirTreeDeserializer,
functionDeserializer = FunctionCirTreeDeserializer,
typeAliasDeserializer = TypeAliasCirTreeDeserializer,
classDeserializer = ClassCirTreeDeserializer(
propertyDeserializer = PropertyCirTreeDeserializer,
functionDeserializer = FunctionCirTreeDeserializer,
constructorDeserializer = ClassConstructorCirTreeDeserializer
)
)
)
)
internal fun deserialize(parameters: CommonizerParameters, target: TargetProvider): CirTreeRoot {
return defaultRootCirTreeDeserializer(parameters, target)
}
@@ -0,0 +1,90 @@
/*
* Copyright 2010-2021 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.commonizer.tree.merger
import org.jetbrains.kotlin.commonizer.TargetDependent
import org.jetbrains.kotlin.commonizer.cir.CirRoot
import org.jetbrains.kotlin.commonizer.mergedtree.*
import org.jetbrains.kotlin.commonizer.tree.*
import org.jetbrains.kotlin.storage.StorageManager
internal data class TargetBuildingContext(
val storageManager: StorageManager, val classifiers: CirKnownClassifiers, val targets: Int, val targetIndex: Int
)
internal fun mergeCirTree(
storageManager: StorageManager, classifiers: CirKnownClassifiers, roots: TargetDependent<CirTreeRoot>
): CirRootNode {
val node = buildRootNode(storageManager, roots.size)
roots.targets.withIndex().forEach { (targetIndex, target) ->
node.targetDeclarations[targetIndex] = CirRoot.create(target)
node.buildModules(TargetBuildingContext(storageManager, classifiers, roots.size, targetIndex), roots[target].modules)
}
return node
}
internal fun CirRootNode.buildModules(context: TargetBuildingContext, modules: List<CirTreeModule>) {
modules.forEach { module -> buildModule(context, module) }
}
internal fun CirRootNode.buildModule(context: TargetBuildingContext, treeModule: CirTreeModule) {
val moduleNode = modules.getOrPut(treeModule.module.name) {
buildModuleNode(context.storageManager, context.targets)
}
moduleNode.targetDeclarations[context.targetIndex] = treeModule.module
treeModule.packages.forEach { pkg -> moduleNode.buildPackage(context, pkg) }
}
internal fun CirModuleNode.buildPackage(context: TargetBuildingContext, treePackage: CirTreePackage) {
val packageNode = packages.getOrPut(treePackage.pkg.packageName) {
buildPackageNode(context.storageManager, context.targets)
}
packageNode.targetDeclarations[context.targetIndex] = treePackage.pkg
treePackage.functions.forEach { function -> packageNode.buildFunction(context, function) }
treePackage.properties.forEach { property -> packageNode.buildProperty(context, property) }
treePackage.typeAliases.forEach { typeAlias -> packageNode.buildTypeAlias(context, typeAlias) }
treePackage.classes.forEach { clazz -> packageNode.buildClass(context, clazz) }
}
internal fun CirNodeWithMembers<*, *>.buildClass(context: TargetBuildingContext, treeClass: CirTreeClass) {
val classNode = classes.getOrPut(treeClass.clazz.name) {
buildClassNode(context.storageManager, context.targets, context.classifiers, treeClass.id)
}
classNode.targetDeclarations[context.targetIndex] = treeClass.clazz
treeClass.functions.forEach { function -> classNode.buildFunction(context, function) }
treeClass.properties.forEach { property -> classNode.buildProperty(context, property) }
treeClass.constructors.forEach { constructor -> classNode.buildConstructor(context, constructor) }
treeClass.classes.forEach { clazz -> classNode.buildClass(context, clazz) }
}
internal fun CirNodeWithMembers<*, *>.buildFunction(context: TargetBuildingContext, treeFunction: CirTreeFunction) {
val functionNode = functions.getOrPut(treeFunction.approximationKey) {
buildFunctionNode(context.storageManager, context.targets, context.classifiers)
}
functionNode.targetDeclarations[context.targetIndex] = treeFunction.function
}
internal fun CirNodeWithMembers<*, *>.buildProperty(context: TargetBuildingContext, treeProperty: CirTreeProperty) {
val propertyNode = properties.getOrPut(treeProperty.approximationKey) {
buildPropertyNode(context.storageManager, context.targets, context.classifiers)
}
propertyNode.targetDeclarations[context.targetIndex] = treeProperty.property
}
internal fun CirClassNode.buildConstructor(context: TargetBuildingContext, treeConstructor: CirTreeClassConstructor) {
val constructorNode = constructors.getOrPut(treeConstructor.approximationKey) {
buildClassConstructorNode(context.storageManager, context.targets, context.classifiers)
}
constructorNode.targetDeclarations[context.targetIndex] = treeConstructor.constructor
}
internal fun CirPackageNode.buildTypeAlias(context: TargetBuildingContext, treeTypeAlias: CirTreeTypeAlias) {
val typeAliasNode = typeAliases.getOrPut(treeTypeAlias.typeAlias.name) {
buildTypeAliasNode(context.storageManager, context.targets, context.classifiers, treeTypeAlias.id)
}
typeAliasNode.targetDeclarations[context.targetIndex] = treeTypeAlias.typeAlias
}
@@ -16,15 +16,15 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.impl.ExportedF
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.commonizer.ResultsConsumer.ModuleResult
import org.jetbrains.kotlin.commonizer.ResultsConsumer.Status
import org.jetbrains.kotlin.commonizer.SourceModuleRoot.Companion.SHARED_TARGET_NAME
import org.jetbrains.kotlin.commonizer.konan.NativeManifestDataProvider
import org.jetbrains.kotlin.commonizer.utils.*
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
@@ -208,7 +208,7 @@ private class AnalyzedModules(
resultsConsumer: ResultsConsumer,
manifestDataProvider: NativeManifestDataProvider = MockNativeManifestDataProvider()
) = CommonizerParameters(
targetProviders = leafTargets.map { leafTarget ->
targetProviders = TargetDependent(leafTargets) { leafTarget ->
TargetProvider(
target = leafTarget,
modulesProvider = MockModulesProvider.create(originalModules.getValue(leafTarget)),
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.commonizer
import org.jetbrains.kotlin.commonizer.ResultsConsumer.ModuleResult
import org.jetbrains.kotlin.commonizer.ResultsConsumer.Status
import org.jetbrains.kotlin.commonizer.konan.NativeManifestDataProvider
import org.jetbrains.kotlin.commonizer.utils.MockResultsConsumer
import org.jetbrains.kotlin.commonizer.utils.MockModulesProvider
import org.jetbrains.kotlin.commonizer.utils.MockNativeManifestDataProvider
import org.jetbrains.kotlin.commonizer.utils.MockResultsConsumer
import org.junit.Test
import kotlin.contracts.ExperimentalContracts
import kotlin.test.assertEquals
@@ -69,14 +69,15 @@ class CommonizerFacadeTest {
resultsConsumer: ResultsConsumer,
manifestDataProvider: NativeManifestDataProvider = MockNativeManifestDataProvider()
) = CommonizerParameters(
targetProviders = map { (targetName, moduleNames) ->
TargetProvider(
target = LeafCommonizerTarget(targetName),
modulesProvider = MockModulesProvider.create(moduleNames),
dependencyModulesProvider = null,
manifestProvider = manifestDataProvider,
)
},
targetProviders = mapKeys { (targetName, _) -> LeafCommonizerTarget(targetName) }.toTargetDependent()
.map { target, moduleNames ->
TargetProvider(
target = target,
modulesProvider = MockModulesProvider.create(moduleNames),
dependencyModulesProvider = null,
manifestProvider = manifestDataProvider,
)
},
resultsConsumer = resultsConsumer,
commonManifestProvider = manifestDataProvider
)