[Commonizer] Optimized implementation of CirProvidedClassifiers
Read classifiers directly from metadata, don't use descriptors.
This commit is contained in:
@@ -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()
|
||||
|
||||
+14
@@ -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>) : CirProvidedClassifiers {
|
||||
constructor(vararg delegates: CirProvidedClassifiers) : this(delegates.toList())
|
||||
|
||||
override fun hasClassifier(classifierId: CirEntityId): Boolean = delegates.any { it.hasClassifier(classifierId) }
|
||||
}
|
||||
+32
@@ -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<CirEntityId> = THashSet<CirEntityId>().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"))
|
||||
}
|
||||
+67
@@ -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<CirEntityId> = 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<CirEntityId> {
|
||||
val result = THashSet<CirEntityId>()
|
||||
|
||||
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<ProtoBuf.Class> = packageFragment.class_List
|
||||
val typeAliases: List<ProtoBuf.TypeAlias> = 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
|
||||
}
|
||||
+4
-44
@@ -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<ModuleDescriptor>) = object : CirProvidedClassifiers {
|
||||
private val nonEmptyMemberScopes: Map<CirPackageName, MemberScope> by storageManager.createLazyValue {
|
||||
THashMap<CirPackageName, MemberScope>().apply {
|
||||
for (module in modules()) {
|
||||
module.collectNonEmptyPackageMemberScopes(probeRootPackageForEmptiness = true) { packageName, memberScope ->
|
||||
this[packageName] = memberScope
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val presentClassifiers = THashSet<CirEntityId>()
|
||||
private val missingClassifiers = THashSet<CirEntityId>()
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user