diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/facade.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/facade.kt index e85620ef3c0..41f164369ce 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/facade.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/facade.kt @@ -43,9 +43,10 @@ private fun mergeAndCommonize(storageManager: StorageManager, parameters: Common forwardDeclarations = CirForwardDeclarations.default(), dependencies = mapOf( // for now, supply only common dependency libraries (ex: Kotlin stdlib) - parameters.sharedTarget to CirProvidedClassifiers.fromModules(storageManager) { - parameters.dependencyModulesProvider?.loadModules(emptyList())?.values.orEmpty() - } + parameters.sharedTarget to CirCompositeClassifiers( + CirFictitiousFunctionClassifiers, + CirLoadedClassifiers.from(parameters.dependencyModulesProvider) + ) ) ) val mergeResult = CirTreeMerger(storageManager, classifiers, parameters).merge() diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirCompositeClassifiers.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirCompositeClassifiers.kt new file mode 100644 index 00000000000..b92faa5a278 --- /dev/null +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirCompositeClassifiers.kt @@ -0,0 +1,14 @@ +/* + * 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.descriptors.commonizer.mergedtree + +import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId + +class CirCompositeClassifiers(private val delegates: List) : CirProvidedClassifiers { + constructor(vararg delegates: CirProvidedClassifiers) : this(delegates.toList()) + + override fun hasClassifier(classifierId: CirEntityId): Boolean = delegates.any { it.hasClassifier(classifierId) } +} diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirFictitiousFunctionClassifiers.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirFictitiousFunctionClassifiers.kt new file mode 100644 index 00000000000..eb4a8699c86 --- /dev/null +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirFictitiousFunctionClassifiers.kt @@ -0,0 +1,32 @@ +/* + * 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.descriptors.commonizer.mergedtree + +import gnu.trove.THashSet +import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId +import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName +import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName + +object CirFictitiousFunctionClassifiers : CirProvidedClassifiers { + private const val MIN_ARITY = 0 + private const val MAX_ARITY = 255 + + private val FUNCTION_PREFIXES = arrayOf("Function", "SuspendFunction") + private val PACKAGE_NAME = CirPackageName.create("kotlin") + + private val classifiers: Set = THashSet().apply { + (MIN_ARITY..MAX_ARITY).forEach { arity -> + FUNCTION_PREFIXES.forEach { prefix -> + this += buildFictitiousFunctionClass(prefix, arity) + } + } + } + + override fun hasClassifier(classifierId: CirEntityId): Boolean = classifierId in classifiers + + private fun buildFictitiousFunctionClass(prefix: String, arity: Int): CirEntityId = + CirEntityId.create(PACKAGE_NAME, CirName.create("$prefix$arity")) +} diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirLoadedClassifiers.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirLoadedClassifiers.kt new file mode 100644 index 00000000000..60a0275655c --- /dev/null +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/CirLoadedClassifiers.kt @@ -0,0 +1,67 @@ +/* + * 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.descriptors.commonizer.mergedtree + +import gnu.trove.THashSet +import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider +import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId +import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName +import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName +import org.jetbrains.kotlin.library.metadata.parsePackageFragment +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl + +class CirLoadedClassifiers(modulesProvider: ModulesProvider) : CirProvidedClassifiers { + private val classifiers: Set = loadClassifiers(modulesProvider) + + override fun hasClassifier(classifierId: CirEntityId): Boolean = classifierId in classifiers + + companion object { + fun from(modulesProvider: ModulesProvider?): CirProvidedClassifiers = + if (modulesProvider != null) CirLoadedClassifiers(modulesProvider) else CirProvidedClassifiers.EMPTY + } +} + +private fun loadClassifiers(modulesProvider: ModulesProvider): Set { + val result = THashSet() + + modulesProvider.loadModuleInfos().forEach { moduleInfo -> + val metadata = modulesProvider.loadModuleMetadata(moduleInfo.name) + + for (i in metadata.fragmentNames.indices) { + val packageFqName = metadata.fragmentNames[i] + val packageFragments = metadata.fragments[i] + + for (j in packageFragments.indices) { + val packageFragment: ProtoBuf.PackageFragment = parsePackageFragment(packageFragments[j]) + + val classes: List = packageFragment.class_List + val typeAliases: List = packageFragment.`package`?.typeAliasList.orEmpty() + + if (classes.isEmpty() && typeAliases.isEmpty()) + break // this and next package fragments do not contain classifiers and can be skipped + + val packageName = CirPackageName.create(packageFqName) + val nameResolver = NameResolverImpl(packageFragment.strings, packageFragment.qualifiedNames) + + for (clazz in classes) { + if (!nameResolver.isLocalClassName(clazz.fqName)) { + val classId = CirEntityId.create(nameResolver.getQualifiedClassName(clazz.fqName)) + check(classId.packageName == packageName) + result += classId + } + } + + for (typeAlias in typeAliases) { + val typeAliasId = CirEntityId.create(packageName, CirName.create(nameResolver.getString(typeAlias.name))) + result += typeAliasId + } + } + } + } + + return result +} diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/classifierContainers.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/classifierContainers.kt index 0f2624405ea..eb5835ac479 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/classifierContainers.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/classifierContainers.kt @@ -7,16 +7,10 @@ package org.jetbrains.kotlin.descriptors.commonizer.mergedtree import gnu.trove.THashMap import gnu.trove.THashSet -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget +import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId -import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName import org.jetbrains.kotlin.descriptors.commonizer.utils.isUnderKotlinNativeSyntheticPackages -import org.jetbrains.kotlin.descriptors.commonizer.utils.resolveClassOrTypeAlias -import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.storage.StorageManager -import org.jetbrains.kotlin.storage.getValue class CirKnownClassifiers( val commonized: CirCommonizedClassifiers, @@ -28,6 +22,7 @@ class CirKnownClassifiers( dependencies.filterKeys { it is SharedCommonizerTarget }.values.singleOrNull() ?: CirProvidedClassifiers.EMPTY } +/** A set of all CIR nodes built for commonized classes and type aliases. */ interface CirCommonizedClassifiers { /* Accessors */ fun classNode(classId: CirEntityId): CirClassNode? @@ -58,6 +53,7 @@ interface CirCommonizedClassifiers { } } +/** A set of all exported forward declaration classes/objects/structs. */ interface CirForwardDeclarations { /* Accessors */ fun isExportedForwardDeclaration(classId: CirEntityId): Boolean @@ -79,6 +75,7 @@ interface CirForwardDeclarations { } } +/** A set of classes and type aliases provided by libraries (either the libraries to commonize, or their dependency libraries)/ */ interface CirProvidedClassifiers { fun hasClassifier(classifierId: CirEntityId): Boolean @@ -89,42 +86,5 @@ interface CirProvidedClassifiers { internal val EMPTY = object : CirProvidedClassifiers { override fun hasClassifier(classifierId: CirEntityId) = false } - - // N.B. This is suboptimal implementation. It will be replaced by another implementation that will - // retrieve classifier information directly from the metadata. - fun fromModules(storageManager: StorageManager, modules: () -> Collection) = object : CirProvidedClassifiers { - private val nonEmptyMemberScopes: Map by storageManager.createLazyValue { - THashMap().apply { - for (module in modules()) { - module.collectNonEmptyPackageMemberScopes(probeRootPackageForEmptiness = true) { packageName, memberScope -> - this[packageName] = memberScope - } - } - } - } - - private val presentClassifiers = THashSet() - private val missingClassifiers = THashSet() - - override fun hasClassifier(classifierId: CirEntityId): Boolean { - if (classifierId.relativeNameSegments.isEmpty()) - return false - - val memberScope = nonEmptyMemberScopes[classifierId.packageName] ?: return false - - return when (classifierId) { - in presentClassifiers -> true - in missingClassifiers -> false - else -> { - val found = memberScope.resolveClassOrTypeAlias(classifierId.relativeNameSegments) != null - when (found) { - true -> presentClassifiers += classifierId - false -> missingClassifiers += classifierId - } - found - } - } - } - } } } diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/collectors.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/collectors.kt index ba08a232890..ca4d487a75b 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/collectors.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/mergedtree/collectors.kt @@ -64,23 +64,17 @@ internal inline fun FunctionCollector( } // collects member scopes for every non-empty package provided by this module -internal fun ModuleDescriptor.collectNonEmptyPackageMemberScopes( - probeRootPackageForEmptiness: Boolean = false, // false is the default as probing might be expensive and is not always necessary - collector: (CirPackageName, MemberScope) -> Unit -) { +internal fun ModuleDescriptor.collectNonEmptyPackageMemberScopes(collector: (CirPackageName, MemberScope) -> Unit) { // we don's need to process fragments from other modules which are the dependencies of this module, so // let's use the appropriate package fragment provider val packageFragmentProvider = this.packageFragmentProvider fun recurse(packageFqName: FqName) { - val probeForEmptiness = probeRootPackageForEmptiness && packageFqName.isRoot - val ownPackageMemberScopes = packageFragmentProvider.packageFragments(packageFqName) .asSequence() .filter { it !is ExportedForwardDeclarationsPackageFragmentDescriptor && it !is ClassifierAliasingPackageFragmentDescriptor } .map { it.getMemberScope() } .filter { it != MemberScope.Empty } - .filter { !probeForEmptiness || it.getContributedDescriptors().isNotEmpty() } .toList() if (ownPackageMemberScopes.isNotEmpty()) {