[Commonizer] Log stats during building metadata

This commit is contained in:
Dmitriy Dolovov
2021-01-27 17:16:59 +03:00
parent d610837caf
commit 4c640e3f81
19 changed files with 653 additions and 435 deletions
@@ -30,9 +30,6 @@ internal fun CirClassNode.buildDescriptors(
} }
commonClass?.buildDescriptor(components, output, indexOfCommon, containingDeclarations, classId, isExpect = true) commonClass?.buildDescriptor(components, output, indexOfCommon, containingDeclarations, classId, isExpect = true)
// log stats
components.statsCollector?.logStats(output)
} }
internal fun CirClass.buildDescriptor( internal fun CirClass.buildDescriptor(
@@ -86,9 +83,6 @@ internal fun CirClassConstructorNode.buildDescriptors(
} }
commonConstructor?.buildDescriptor(components, output, indexOfCommon, containingDeclarations, isExpect = true) commonConstructor?.buildDescriptor(components, output, indexOfCommon, containingDeclarations, isExpect = true)
// log stats
components.statsCollector?.logStats(output)
} }
private fun CirClassConstructor.buildDescriptor( private fun CirClassConstructor.buildDescriptor(
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode.Companion.dimension import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode.Companion.dimension
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode.Companion.indexOfCommon import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode.Companion.indexOfCommon
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirRootNode import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirRootNode
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
import org.jetbrains.kotlin.descriptors.commonizer.utils.* import org.jetbrains.kotlin.descriptors.commonizer.utils.*
import org.jetbrains.kotlin.descriptors.commonizer.utils.CommonizedGroupMap import org.jetbrains.kotlin.descriptors.commonizer.utils.CommonizedGroupMap
import org.jetbrains.kotlin.descriptors.commonizer.utils.createKotlinNativeForwardDeclarationsModule import org.jetbrains.kotlin.descriptors.commonizer.utils.createKotlinNativeForwardDeclarationsModule
@@ -121,8 +120,7 @@ class DeclarationsBuilderCache(private val dimension: Int) {
class GlobalDeclarationsBuilderComponents( class GlobalDeclarationsBuilderComponents(
val storageManager: StorageManager, val storageManager: StorageManager,
val targetComponents: List<TargetDeclarationsBuilderComponents>, val targetComponents: List<TargetDeclarationsBuilderComponents>,
val cache: DeclarationsBuilderCache, val cache: DeclarationsBuilderCache
val statsCollector: StatsCollector?
) { ) {
init { init {
check(targetComponents.size > 1) check(targetComponents.size > 1)
@@ -274,7 +272,7 @@ fun CirRootNode.createGlobalBuilderComponents(
) )
} }
return GlobalDeclarationsBuilderComponents(storageManager, targetContexts, cache, parameters.statsCollector) return GlobalDeclarationsBuilderComponents(storageManager, targetContexts, cache)
} }
interface TypeParameterResolver { interface TypeParameterResolver {
@@ -28,9 +28,6 @@ internal fun CirFunctionNode.buildDescriptors(
} }
commonFunction?.buildDescriptor(components, output, indexOfCommon, containingDeclarations, isExpect = markAsExpectAndActual) commonFunction?.buildDescriptor(components, output, indexOfCommon, containingDeclarations, isExpect = markAsExpectAndActual)
// log stats
components.statsCollector?.logStats(output)
} }
private fun CirFunction.buildDescriptor( private fun CirFunction.buildDescriptor(
@@ -20,9 +20,6 @@ internal fun CirModuleNode.buildDescriptors(
} }
commonDeclaration()?.buildDescriptor(components, output, indexOfCommon) commonDeclaration()?.buildDescriptor(components, output, indexOfCommon)
// log stats
components.statsCollector?.logStats(output)
} }
private fun CirModule.buildDescriptor( private fun CirModule.buildDescriptor(
@@ -37,9 +37,6 @@ internal fun CirPropertyNode.buildDescriptors(
} }
commonProperty?.buildDescriptor(components, output, indexOfCommon, containingDeclarations, isExpect = markAsExpectAndActual) commonProperty?.buildDescriptor(components, output, indexOfCommon, containingDeclarations, isExpect = markAsExpectAndActual)
// log stats
components.statsCollector?.logStats(output)
} }
private fun CirProperty.buildDescriptor( private fun CirProperty.buildDescriptor(
@@ -41,9 +41,6 @@ internal fun CirTypeAliasNode.buildDescriptors(
} else if (commonClassifier != null && commonClassifier is CirClass) { } else if (commonClassifier != null && commonClassifier is CirClass) {
commonClassifier.buildDescriptor(components, output, indexOfCommon, containingDeclarations, classId, isExpect = true) commonClassifier.buildDescriptor(components, output, indexOfCommon, containingDeclarations, classId, isExpect = true)
} }
// log stats
components.statsCollector?.logStats(output)
} }
private fun CirTypeAlias.buildDescriptor( private fun CirTypeAlias.buildDescriptor(
@@ -43,7 +43,7 @@ fun runCommonization(parameters: CommonizerParameters): CommonizerResult {
// optional part for generating descriptors: end // optional part for generating descriptors: end
for (targetIndex in 0 until mergedTree.dimension) { for (targetIndex in 0 until mergedTree.dimension) {
val (target, metadataModules) = MetadataBuilder.build(mergedTree, targetIndex) val (target, metadataModules) = MetadataBuilder.build(mergedTree, targetIndex, parameters.statsCollector)
// optional part for generating descriptors: begin // optional part for generating descriptors: begin
val moduleDescriptors: Map<String, ModuleDescriptor>? = components?.targetComponents?.get(targetIndex)?.let { component -> val moduleDescriptors: Map<String, ModuleDescriptor>? = components?.targetComponents?.get(targetIndex)?.let { component ->
@@ -10,9 +10,7 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.metadataVersio
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.commonizer.* import org.jetbrains.kotlin.descriptors.commonizer.*
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.StatsType.* import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.StatsType.*
import org.jetbrains.kotlin.descriptors.commonizer.stats.AggregatedStatsCollector import org.jetbrains.kotlin.descriptors.commonizer.stats.*
import org.jetbrains.kotlin.descriptors.commonizer.stats.FileStatsOutput
import org.jetbrains.kotlin.descriptors.commonizer.stats.RawStatsCollector
import org.jetbrains.kotlin.descriptors.commonizer.utils.ResettableClockMark import org.jetbrains.kotlin.descriptors.commonizer.utils.ResettableClockMark
import org.jetbrains.kotlin.konan.library.* import org.jetbrains.kotlin.konan.library.*
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -132,36 +130,38 @@ class NativeDistributionCommonizer(
private fun commonize(allLibraries: AllNativeLibraries): CommonizerResult { private fun commonize(allLibraries: AllNativeLibraries): CommonizerResult {
val statsCollector = when (statsType) { val statsCollector = when (statsType) {
RAW -> RawStatsCollector(targets, FileStatsOutput(destination, "raw")) RAW -> RawStatsCollector(targets)
AGGREGATED -> AggregatedStatsCollector(targets, FileStatsOutput(destination, "aggregated")) AGGREGATED -> AggregatedStatsCollector(targets)
NONE -> null NONE -> null
} }
statsCollector.use {
val parameters = CommonizerParameters(statsCollector, ::logProgress).apply {
val storageManager = LockBasedStorageManager("Commonized modules")
val stdlibProvider = NativeDistributionStdlibProvider(storageManager, allLibraries.stdlib) val parameters = CommonizerParameters(statsCollector, ::logProgress).apply {
dependeeModulesProvider = stdlibProvider val storageManager = LockBasedStorageManager("Commonized modules")
allLibraries.librariesByTargets.forEach { (target, librariesToCommonize) -> val stdlibProvider = NativeDistributionStdlibProvider(storageManager, allLibraries.stdlib)
if (librariesToCommonize.libraries.isEmpty()) return@forEach dependeeModulesProvider = stdlibProvider
val modulesProvider = NativeDistributionModulesProvider(storageManager, librariesToCommonize) allLibraries.librariesByTargets.forEach { (target, librariesToCommonize) ->
if (librariesToCommonize.libraries.isEmpty()) return@forEach
addTarget( val modulesProvider = NativeDistributionModulesProvider(storageManager, librariesToCommonize)
TargetProvider(
target = target, addTarget(
builtInsClass = KonanBuiltIns::class.java, TargetProvider(
builtInsProvider = stdlibProvider, target = target,
modulesProvider = modulesProvider, builtInsClass = KonanBuiltIns::class.java,
dependeeModulesProvider = null // stdlib is already set as common dependency builtInsProvider = stdlibProvider,
) modulesProvider = modulesProvider,
dependeeModulesProvider = null // stdlib is already set as common dependency
) )
} )
} }
return runCommonization(parameters)
} }
val result = runCommonization(parameters)
statsCollector?.writeTo(FileStatsOutput(destination, statsType.name.toLowerCase()))
return result
} }
private fun saveModules(originalLibraries: AllNativeLibraries, result: CommonizerResult) { private fun saveModules(originalLibraries: AllNativeLibraries, result: CommonizerResult) {
@@ -15,8 +15,8 @@ import org.jetbrains.kotlin.name.Name
/** Used for approximation of [PropertyDescriptor]s before running concrete [Commonizer]s */ /** Used for approximation of [PropertyDescriptor]s before running concrete [Commonizer]s */
data class PropertyApproximationKey( data class PropertyApproximationKey(
private val name: Name, val name: Name,
private val extensionReceiverParameterType: CirTypeSignature? val extensionReceiverParameterType: CirTypeSignature?
) { ) {
constructor(property: PropertyDescriptor) : this( constructor(property: PropertyDescriptor) : this(
property.name.intern(), property.name.intern(),
@@ -26,10 +26,10 @@ data class PropertyApproximationKey(
/** Used for approximation of [SimpleFunctionDescriptor]s before running concrete [Commonizer]s */ /** Used for approximation of [SimpleFunctionDescriptor]s before running concrete [Commonizer]s */
data class FunctionApproximationKey( data class FunctionApproximationKey(
private val name: Name, val name: Name,
private val valueParametersTypes: Array<CirTypeSignature>, val valueParametersTypes: Array<CirTypeSignature>,
private val additionalValueParametersNamesHash: Int, private val additionalValueParametersNamesHash: Int,
private val extensionReceiverParameterType: CirTypeSignature? val extensionReceiverParameterType: CirTypeSignature?
) { ) {
constructor(function: SimpleFunctionDescriptor) : this( constructor(function: SimpleFunctionDescriptor) : this(
function.name.intern(), function.name.intern(),
@@ -56,7 +56,7 @@ data class FunctionApproximationKey(
/** Used for approximation of [ConstructorDescriptor]s before running concrete [Commonizer]s */ /** Used for approximation of [ConstructorDescriptor]s before running concrete [Commonizer]s */
data class ConstructorApproximationKey( data class ConstructorApproximationKey(
private val valueParametersTypes: Array<CirTypeSignature>, val valueParametersTypes: Array<CirTypeSignature>,
private val additionalValueParametersNamesHash: Int private val additionalValueParametersNamesHash: Int
) { ) {
constructor(constructor: ConstructorDescriptor) : this( constructor(constructor: ConstructorDescriptor) : this(
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.commonizer.cir.impl.CirValueParameterImp
import org.jetbrains.kotlin.descriptors.commonizer.core.computeExpandedType import org.jetbrains.kotlin.descriptors.commonizer.core.computeExpandedType
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.* import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
import org.jetbrains.kotlin.descriptors.commonizer.metadata.TypeAliasExpansion.* import org.jetbrains.kotlin.descriptors.commonizer.metadata.TypeAliasExpansion.*
import org.jetbrains.kotlin.descriptors.commonizer.utils.DEFAULT_SETTER_VALUE_NAME
import org.jetbrains.kotlin.descriptors.commonizer.utils.strip import org.jetbrains.kotlin.descriptors.commonizer.utils.strip
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -72,7 +73,7 @@ internal fun addEmptyFragments(fragments: MutableCollection<KmModuleFragment>) {
} }
internal fun CirClass.buildClass( internal fun CirClass.buildClass(
context: VisitingContext, context: MetadataBuildingVisitorContext,
className: ClassName, className: ClassName,
directNestedClasses: Collection<KmClass>, directNestedClasses: Collection<KmClass>,
nestedConstructors: Collection<KmConstructor>, nestedConstructors: Collection<KmConstructor>,
@@ -122,7 +123,7 @@ internal fun linkSealedClassesWithSubclasses(packageFqName: FqName, classConsume
} }
internal fun CirClassConstructor.buildClassConstructor( internal fun CirClassConstructor.buildClassConstructor(
context: VisitingContext context: MetadataBuildingVisitorContext
): KmConstructor = KmConstructor( ): KmConstructor = KmConstructor(
flags = classConstructorFlags() flags = classConstructorFlags()
).also { constructor -> ).also { constructor ->
@@ -131,7 +132,7 @@ internal fun CirClassConstructor.buildClassConstructor(
} }
internal fun CirTypeAlias.buildTypeAlias( internal fun CirTypeAlias.buildTypeAlias(
context: VisitingContext context: MetadataBuildingVisitorContext
): KmTypeAlias = KmTypeAlias( ): KmTypeAlias = KmTypeAlias(
flags = typeAliasFlags(), flags = typeAliasFlags(),
name = name.asString() name = name.asString()
@@ -143,7 +144,7 @@ internal fun CirTypeAlias.buildTypeAlias(
} }
internal fun CirProperty.buildProperty( internal fun CirProperty.buildProperty(
context: VisitingContext, context: MetadataBuildingVisitorContext,
): KmProperty = KmProperty( ): KmProperty = KmProperty(
flags = propertyFlags(isExpect = context.isCommon && !isLiftedUp), flags = propertyFlags(isExpect = context.isCommon && !isLiftedUp),
name = name.asString(), name = name.asString(),
@@ -162,7 +163,7 @@ internal fun CirProperty.buildProperty(
setter?.takeIf { !it.isDefault }?.let { setter -> setter?.takeIf { !it.isDefault }?.let { setter ->
property.setterParameter = CirValueParameterImpl( property.setterParameter = CirValueParameterImpl(
annotations = setter.parameterAnnotations, annotations = setter.parameterAnnotations,
name = SETTER_VALUE_NAME, name = DEFAULT_SETTER_VALUE_NAME,
returnType = returnType, returnType = returnType,
varargElementType = null, varargElementType = null,
declaresDefaultValue = false, declaresDefaultValue = false,
@@ -174,7 +175,7 @@ internal fun CirProperty.buildProperty(
} }
internal fun CirFunction.buildFunction( internal fun CirFunction.buildFunction(
context: VisitingContext, context: MetadataBuildingVisitorContext,
): KmFunction = KmFunction( ): KmFunction = KmFunction(
flags = functionFlags(isExpect = context.isCommon), flags = functionFlags(isExpect = context.isCommon),
name = name.asString() name = name.asString()
@@ -231,7 +232,7 @@ private fun ConstantValue<*>.buildAnnotationArgument(): KmAnnotationArgument<*>
} }
private fun CirValueParameter.buildValueParameter( private fun CirValueParameter.buildValueParameter(
context: VisitingContext context: MetadataBuildingVisitorContext
): KmValueParameter = KmValueParameter( ): KmValueParameter = KmValueParameter(
flags = valueParameterFlags(), flags = valueParameterFlags(),
name = name.asString() name = name.asString()
@@ -244,7 +245,7 @@ private fun CirValueParameter.buildValueParameter(
} }
private fun List<CirTypeParameter>.buildTypeParameters( private fun List<CirTypeParameter>.buildTypeParameters(
context: VisitingContext, context: MetadataBuildingVisitorContext,
output: MutableList<KmTypeParameter> output: MutableList<KmTypeParameter>
) { ) {
mapIndexedTo(output) { index, cirTypeParameter -> mapIndexedTo(output) { index, cirTypeParameter ->
@@ -261,7 +262,7 @@ private fun List<CirTypeParameter>.buildTypeParameters(
} }
private fun CirType.buildType( private fun CirType.buildType(
context: VisitingContext, context: MetadataBuildingVisitorContext,
expansion: TypeAliasExpansion = FOR_TOP_LEVEL_TYPE expansion: TypeAliasExpansion = FOR_TOP_LEVEL_TYPE
): KmType = when (this) { ): KmType = when (this) {
is CirClassType -> buildType(context, expansion) is CirClassType -> buildType(context, expansion)
@@ -283,7 +284,7 @@ private fun CirTypeParameterType.buildType(): KmType =
} }
private fun CirClassType.buildType( private fun CirClassType.buildType(
context: VisitingContext, context: MetadataBuildingVisitorContext,
expansion: TypeAliasExpansion expansion: TypeAliasExpansion
): KmType = KmType(typeFlags()).also { type -> ): KmType = KmType(typeFlags()).also { type ->
type.classifier = KmClassifier.Class(classifierId.asString()) type.classifier = KmClassifier.Class(classifierId.asString())
@@ -292,7 +293,7 @@ private fun CirClassType.buildType(
} }
private fun CirTypeAliasType.buildType( private fun CirTypeAliasType.buildType(
context: VisitingContext, context: MetadataBuildingVisitorContext,
expansion: TypeAliasExpansion expansion: TypeAliasExpansion
): KmType = when (expansion) { ): KmType = when (expansion) {
ONLY_ABBREVIATIONS -> buildAbbreviationType(context, expansion) ONLY_ABBREVIATIONS -> buildAbbreviationType(context, expansion)
@@ -306,7 +307,7 @@ private fun CirTypeAliasType.buildType(
} }
private fun CirTypeAliasType.buildAbbreviationType( private fun CirTypeAliasType.buildAbbreviationType(
context: VisitingContext, context: MetadataBuildingVisitorContext,
expansion: TypeAliasExpansion expansion: TypeAliasExpansion
): KmType { ): KmType {
val abbreviationType = KmType(typeFlags()) val abbreviationType = KmType(typeFlags())
@@ -317,7 +318,7 @@ private fun CirTypeAliasType.buildAbbreviationType(
@Suppress("UnnecessaryVariable") @Suppress("UnnecessaryVariable")
private fun CirTypeAliasType.buildExpandedType( private fun CirTypeAliasType.buildExpandedType(
context: VisitingContext, context: MetadataBuildingVisitorContext,
expansion: TypeAliasExpansion expansion: TypeAliasExpansion
): KmType { ): KmType {
val cirExpandedType = computeExpandedType(underlyingType) val cirExpandedType = computeExpandedType(underlyingType)
@@ -326,7 +327,7 @@ private fun CirTypeAliasType.buildExpandedType(
} }
private fun CirTypeProjection.buildArgument( private fun CirTypeProjection.buildArgument(
context: VisitingContext, context: MetadataBuildingVisitorContext,
expansion: TypeAliasExpansion expansion: TypeAliasExpansion
): KmTypeProjection { ): KmTypeProjection {
val effectiveExpansion = if (expansion == FOR_TOP_LEVEL_TYPE) FOR_NESTED_TYPE else expansion val effectiveExpansion = if (expansion == FOR_TOP_LEVEL_TYPE) FOR_NESTED_TYPE else expansion
@@ -353,5 +354,3 @@ private enum class TypeAliasExpansion {
FOR_TOP_LEVEL_TYPE, FOR_TOP_LEVEL_TYPE,
FOR_NESTED_TYPE FOR_NESTED_TYPE
} }
private val SETTER_VALUE_NAME = Name.identifier("value")
@@ -0,0 +1,452 @@
/*
* 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.metadata
import kotlinx.metadata.*
import kotlinx.metadata.klib.KlibModuleMetadata
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode.Companion.indexOfCommon
import org.jetbrains.kotlin.descriptors.commonizer.stats.DeclarationType
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector.StatsKey
import org.jetbrains.kotlin.descriptors.commonizer.utils.DEFAULT_CONSTRUCTOR_NAME
import org.jetbrains.kotlin.descriptors.commonizer.utils.strip
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.descriptors.commonizer.utils.firstNonNull
import org.jetbrains.kotlin.descriptors.commonizer.metadata.MetadataBuildingVisitorContext.Path
internal object MetadataBuilder {
fun build(
node: CirRootNode,
targetIndex: Int,
statsCollector: StatsCollector?
): Pair<CommonizerTarget, Collection<KlibModuleMetadata>> {
return node.accept(
MetadataBuildingVisitor(statsCollector),
MetadataBuildingVisitorContext.rootContext(node, targetIndex)
).cast()
}
}
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
private class MetadataBuildingVisitor(private val statsCollector: StatsCollector?) : CirNodeVisitor<MetadataBuildingVisitorContext, Any?> {
private val classConsumer = ClassConsumer()
override fun visitRootNode(
node: CirRootNode,
rootContext: MetadataBuildingVisitorContext
): Pair<CommonizerTarget, Collection<KlibModuleMetadata>> {
val modules: List<KlibModuleMetadata> = node.modules.mapNotNull { (moduleName, moduleNode) ->
val moduleContext = rootContext.moduleContext(moduleName)
val module: KlibModuleMetadata? = moduleNode.accept(this, moduleContext)?.cast()
statsCollector?.logModule(moduleContext)
module
}
return rootContext.target to modules
}
override fun visitModuleNode(
node: CirModuleNode,
moduleContext: MetadataBuildingVisitorContext
): KlibModuleMetadata? {
val cirModule = moduleContext.get<CirModule>(node) ?: return null
val fragments: MutableCollection<KmModuleFragment> = mutableListOf()
node.packages.mapNotNullTo(fragments) { (packageFqName, packageNode) ->
val packageContext = moduleContext.packageContext(packageFqName)
packageNode.accept(this, packageContext)?.cast()
}
addEmptyFragments(fragments)
return cirModule.buildModule(fragments)
}
override fun visitPackageNode(
node: CirPackageNode,
packageContext: MetadataBuildingVisitorContext
): KmModuleFragment? {
val cirPackage = packageContext.get<CirPackage>(node) ?: return null
try {
node.classes.forEach { (className, classNode) ->
val classContext = packageContext.classifierContext(className)
val clazz: KmClass = classNode.accept(this, classContext)?.cast() ?: return@forEach
classConsumer.consume(clazz)
statsCollector?.logClass(clazz, classContext)
}
val topLevelTypeAliases = mutableListOf<KmTypeAlias>()
node.typeAliases.forEach { (typeAliasName, typeAliasNode) ->
val typeAliasContext = packageContext.classifierContext(typeAliasName)
when (val classifier = typeAliasNode.accept(this, typeAliasContext)) {
null -> Unit
is KmClass -> {
classConsumer.consume(classifier)
statsCollector?.logClass(classifier, typeAliasContext)
}
is KmTypeAlias -> {
topLevelTypeAliases += classifier
statsCollector?.logTypeAlias(typeAliasContext)
}
else -> error("Unexpected classifier: ${classifier::class.java}, $classifier")
}
}
linkSealedClassesWithSubclasses(cirPackage.fqName, classConsumer)
val topLevelFunctions: Collection<KmFunction> = node.functions.mapNotNull { (functionKey, functionNode) ->
val functionContext = packageContext.callableMemberContext(functionKey.name)
val function: KmFunction = functionNode.accept(this, functionContext)?.cast() ?: return@mapNotNull null
statsCollector?.logFunction(function, functionContext, functionKey)
function
}
val topLevelProperties: Collection<KmProperty> = node.properties.mapNotNull { (propertyKey, propertyNode) ->
val propertyContext = packageContext.callableMemberContext(propertyKey.name)
val property: KmProperty = propertyNode.accept(this, propertyContext)?.cast() ?: return@mapNotNull null
statsCollector?.logProperty(propertyContext, propertyKey, propertyNode)
property
}
return cirPackage.buildModuleFragment(classConsumer.allClasses, topLevelTypeAliases, topLevelFunctions, topLevelProperties)
} finally {
// Important: clean-up class consumer every time when leaving package
classConsumer.reset()
}
}
override fun visitPropertyNode(
node: CirPropertyNode,
propertyContext: MetadataBuildingVisitorContext
): KmProperty? {
return propertyContext.get<CirProperty>(node)?.buildProperty(propertyContext)
}
override fun visitFunctionNode(
node: CirFunctionNode,
functionContext: MetadataBuildingVisitorContext
): KmFunction? {
return functionContext.get<CirFunction>(node)?.buildFunction(functionContext)
}
override fun visitClassNode(
node: CirClassNode,
classContext: MetadataBuildingVisitorContext
): KmClass? {
val cirClass = classContext.get<CirClass>(node) ?: return null
val classTypeParametersCount = cirClass.typeParameters.size
val fullClassName = classContext.currentPath.toString()
val directNestedClasses: Collection<KmClass> = node.classes.mapNotNull { (nestedClassName, nestedClassNode) ->
val isInnerClass = classContext.get<CirClass>(nestedClassNode)?.isInner ?: return@mapNotNull null
val outerClassTypeParametersCount = if (isInnerClass) classTypeParametersCount else 0
val nestedClassContext = classContext.classifierContext(nestedClassName, isInnerClass, outerClassTypeParametersCount)
val nestedClass: KmClass = nestedClassNode.accept(this, nestedClassContext)?.cast() ?: return@mapNotNull null
classConsumer.consume(nestedClass)
statsCollector?.logClass(nestedClass, nestedClassContext)
nestedClass
}
val nestedConstructors: Collection<KmConstructor> = node.constructors.mapNotNull { (constructorKey, constructorNode) ->
val constructorContext = classContext.callableMemberContext(DEFAULT_CONSTRUCTOR_NAME, classTypeParametersCount)
val constructor: KmConstructor = constructorNode.accept(this, constructorContext)?.cast() ?: return@mapNotNull null
statsCollector?.logClassConstructor(constructor, constructorContext, constructorKey)
constructor
}
val nestedFunctions: Collection<KmFunction> = node.functions.mapNotNull { (functionKey, functionNode) ->
val functionContext = classContext.callableMemberContext(functionKey.name, classTypeParametersCount)
val function: KmFunction = functionNode.accept(this, functionContext)?.cast() ?: return@mapNotNull null
statsCollector?.logFunction(function, functionContext, functionKey)
function
}
val nestedProperties: Collection<KmProperty> = node.properties.mapNotNull { (propertyKey, propertyNode) ->
val propertyContext = classContext.callableMemberContext(propertyKey.name, classTypeParametersCount)
val property: KmProperty = propertyNode.accept(this, propertyContext)?.cast() ?: return@mapNotNull null
statsCollector?.logProperty(propertyContext, propertyKey, propertyNode)
property
}
return cirClass.buildClass(classContext, fullClassName, directNestedClasses, nestedConstructors, nestedFunctions, nestedProperties)
}
override fun visitClassConstructorNode(
node: CirClassConstructorNode,
constructorContext: MetadataBuildingVisitorContext
): KmConstructor? {
return constructorContext.get<CirClassConstructor>(node)?.buildClassConstructor(constructorContext)
}
override fun visitTypeAliasNode(
node: CirTypeAliasNode,
typeAliasContext: MetadataBuildingVisitorContext
): Any? {
val cirClassifier = typeAliasContext.get<CirClassifier>(node) ?: return null
return when (cirClassifier) {
is CirTypeAlias -> cirClassifier.buildTypeAlias(typeAliasContext)
is CirClass -> {
val fullClassName = typeAliasContext.currentPath.toString()
cirClassifier.buildClass(typeAliasContext, fullClassName, emptyList(), emptyList(), emptyList(), emptyList())
}
else -> error("Unexpected CIR classifier: ${cirClassifier::class.java}, $cirClassifier")
}
}
companion object {
private fun StatsCollector.logModule(
moduleContext: MetadataBuildingVisitorContext
) = logDeclaration(moduleContext.targetIndex) {
StatsKey(moduleContext.currentPath.toString(), DeclarationType.MODULE)
}
private fun StatsCollector.logClass(
clazz: KmClass,
classContext: MetadataBuildingVisitorContext
) = logDeclaration(classContext.targetIndex) {
val declarationType = when {
Flag.Class.IS_ENUM_CLASS(clazz.flags) -> DeclarationType.ENUM_CLASS
Flag.Class.IS_ENUM_ENTRY(clazz.flags) -> DeclarationType.ENUM_ENTRY
Flag.Class.IS_INTERFACE(clazz.flags) -> when {
(classContext.currentPath as Path.Classifier).classifierId.isNestedClass -> DeclarationType.NESTED_INTERFACE
else -> DeclarationType.TOP_LEVEL_INTERFACE
}
else -> when {
Flag.Class.IS_COMPANION_OBJECT(clazz.flags) -> DeclarationType.COMPANION_OBJECT
(classContext.currentPath as Path.Classifier).classifierId.isNestedClass -> DeclarationType.NESTED_CLASS
else -> DeclarationType.TOP_LEVEL_CLASS
}
}
StatsKey(classContext.currentPath.toString(), declarationType)
}
private fun StatsCollector.logTypeAlias(
typeAliasContext: MetadataBuildingVisitorContext
) = logDeclaration(typeAliasContext.targetIndex) {
StatsKey(typeAliasContext.currentPath.toString(), DeclarationType.TYPE_ALIAS)
}
private fun StatsCollector.logProperty(
propertyContext: MetadataBuildingVisitorContext,
propertyKey: PropertyApproximationKey,
propertyNode: CirPropertyNode
) = logDeclaration(propertyContext.targetIndex) {
val declarationType = when {
(propertyContext.currentPath as Path.CallableMember).memberId.isNestedClass -> DeclarationType.NESTED_VAL
propertyNode.targetDeclarations.firstNonNull().isConst -> DeclarationType.TOP_LEVEL_CONST_VAL
else -> DeclarationType.TOP_LEVEL_VAL
}
StatsKey(
id = propertyContext.currentPath.toString(),
extensionReceiver = propertyKey.extensionReceiverParameterType,
parameterNames = emptyList(),
parameterTypes = emptyList(),
declarationType = declarationType
)
}
private fun StatsCollector.logFunction(
function: KmFunction,
functionContext: MetadataBuildingVisitorContext,
functionKey: FunctionApproximationKey
) = logDeclaration(functionContext.targetIndex) {
val declarationType = when {
(functionContext.currentPath as Path.CallableMember).memberId.isNestedClass -> DeclarationType.NESTED_FUN
else -> DeclarationType.TOP_LEVEL_FUN
}
StatsKey(
id = functionContext.currentPath.toString(),
extensionReceiver = functionKey.extensionReceiverParameterType,
parameterNames = function.valueParameters.map { it.name },
parameterTypes = functionKey.valueParametersTypes.asList(),
declarationType = declarationType
)
}
private fun StatsCollector.logClassConstructor(
constructor: KmConstructor,
constructorContext: MetadataBuildingVisitorContext,
constructorKey: ConstructorApproximationKey
) = logDeclaration(constructorContext.targetIndex) {
StatsKey(
id = constructorContext.currentPath.toString(),
extensionReceiver = null,
parameterNames = constructor.valueParameters.map { it.name },
parameterTypes = constructorKey.valueParametersTypes.asList(),
declarationType = DeclarationType.CLASS_CONSTRUCTOR
)
}
}
}
internal data class MetadataBuildingVisitorContext(
val targetIndex: Int,
val target: CommonizerTarget,
val isCommon: Boolean,
val typeParameterIndexOffset: Int,
val currentPath: Path
) {
sealed class Path {
object Empty : Path() {
override fun toString() = ""
}
class Module(val moduleName: Name) : Path() {
override fun toString() = moduleName.strip()
}
class Package(val packageFqName: FqName) : Path() {
fun nestedClassifier(classifierName: Name) = Classifier(ClassId(packageFqName, classifierName))
fun nestedCallableMember(memberName: Name) = CallableMember(ClassId(packageFqName, memberName))
override fun toString() = packageFqName.asString()
}
class Classifier(val classifierId: ClassId) : Path() {
fun nestedClassifier(classifierName: Name) = Classifier(classifierId.createNestedClassId(classifierName))
fun nestedCallableMember(memberName: Name) = CallableMember(classifierId.createNestedClassId(memberName))
override fun toString() = classifierId.asString()
}
class CallableMember(val memberId: ClassId) : Path() {
override fun toString() = memberId.asString()
}
}
fun moduleContext(moduleName: Name): MetadataBuildingVisitorContext {
check(moduleName.isSpecial)
check(currentPath is Path.Empty)
return MetadataBuildingVisitorContext(
targetIndex = targetIndex,
target = target,
isCommon = isCommon,
typeParameterIndexOffset = 0,
currentPath = Path.Module(moduleName)
)
}
fun packageContext(packageFqName: FqName): MetadataBuildingVisitorContext {
check(currentPath is Path.Module)
return MetadataBuildingVisitorContext(
targetIndex = targetIndex,
target = target,
isCommon = isCommon,
typeParameterIndexOffset = 0,
currentPath = Path.Package(packageFqName)
)
}
fun classifierContext(
classifierName: Name,
isInner: Boolean = false,
outerClassTypeParametersCount: Int = 0
): MetadataBuildingVisitorContext {
val newPath = when (currentPath) {
is Path.Package -> {
check(!isInner)
check(outerClassTypeParametersCount == 0)
currentPath.nestedClassifier(classifierName)
}
is Path.Classifier -> {
check((isInner && outerClassTypeParametersCount >= 0) || (!isInner && outerClassTypeParametersCount == 0))
currentPath.nestedClassifier(classifierName)
}
else -> error("Illegal state")
}
return MetadataBuildingVisitorContext(
targetIndex = targetIndex,
target = target,
isCommon = isCommon,
typeParameterIndexOffset = if (isInner) typeParameterIndexOffset + outerClassTypeParametersCount else 0,
currentPath = newPath
)
}
fun callableMemberContext(
memberName: Name,
ownerClassTypeParametersCount: Int = 0
): MetadataBuildingVisitorContext {
val newPath = when (currentPath) {
is Path.Package -> {
check(ownerClassTypeParametersCount == 0)
currentPath.nestedCallableMember(memberName)
}
is Path.Classifier -> {
check(ownerClassTypeParametersCount >= 0)
currentPath.nestedCallableMember(memberName)
}
else -> error("Illegal state")
}
return MetadataBuildingVisitorContext(
targetIndex = targetIndex,
target = target,
isCommon = isCommon,
typeParameterIndexOffset = typeParameterIndexOffset + ownerClassTypeParametersCount,
currentPath = newPath
)
}
inline fun <reified T : CirDeclaration> get(node: CirNode<*, *>): T? {
return (if (isCommon) node.commonDeclaration() else node.targetDeclarations[targetIndex]) as T?
}
inline fun <reified T : CirDeclaration> get(node: CirNodeWithLiftingUp<*, *>): T? {
return when {
isCommon -> node.commonDeclaration() as T?
node.isLiftedUp -> null
else -> node.targetDeclarations[targetIndex] as T?
}
}
companion object {
fun rootContext(rootNode: CirRootNode, targetIndex: Int): MetadataBuildingVisitorContext {
val isCommon = rootNode.indexOfCommon == targetIndex
val target = (if (isCommon) rootNode.commonDeclaration() else rootNode.targetDeclarations[targetIndex])!!.target
return MetadataBuildingVisitorContext(
targetIndex = targetIndex,
target = target,
isCommon = isCommon,
typeParameterIndexOffset = 0,
currentPath = Path.Empty
)
}
}
}
internal class ClassConsumer {
private val _allClasses = mutableListOf<KmClass>()
private val _sealedClasses = mutableListOf<KmClass>()
val allClasses: Collection<KmClass> get() = _allClasses
val sealedClasses: Collection<KmClass> get() = _sealedClasses
fun consume(clazz: KmClass) {
_allClasses += clazz
if (Flag.Common.IS_SEALED(clazz.flags)) _sealedClasses += clazz
}
fun reset() {
_allClasses.clear()
_sealedClasses.clear()
}
}
@@ -1,60 +0,0 @@
/*
* 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.metadata
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNode.Companion.indexOfCommon
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirNodeWithLiftingUp
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.CirRootNode
internal interface VisitingContext {
val targetIndex: Int
val target: CommonizerTarget
val isCommon: Boolean
val typeParameterIndexOffset: Int
val topLevelContext: VisitingContext
fun childContext(declarationWithTypeParameters: CirHasTypeParameters): VisitingContext {
val ownTypeParametersCount = declarationWithTypeParameters.typeParameters.size
return if (ownTypeParametersCount == 0) this else ChildVisitingContext(this, ownTypeParametersCount)
}
companion object {
fun newContext(rootNode: CirRootNode, targetIndex: Int): VisitingContext =
TopLevelVisitingContext(rootNode, targetIndex)
}
private class TopLevelVisitingContext(
rootNode: CirRootNode,
override val targetIndex: Int
) : VisitingContext {
override val isCommon = rootNode.indexOfCommon == targetIndex
override val target = get<CirRoot>(rootNode)!!.target
override val typeParameterIndexOffset get() = 0
override val topLevelContext: VisitingContext get() = this
}
private class ChildVisitingContext(
private val parent: VisitingContext,
typeParametersCount: Int
) : VisitingContext by parent {
override val typeParameterIndexOffset = parent.typeParameterIndexOffset + typeParametersCount
}
}
internal inline fun <reified T : CirDeclaration> VisitingContext.get(node: CirNodeWithLiftingUp<*, *>): T? {
return when {
isCommon -> node.commonDeclaration() as T?
node.isLiftedUp -> null
else -> node.targetDeclarations[targetIndex] as T?
}
}
internal inline fun <reified T : CirDeclaration> VisitingContext.get(node: CirNode<*, *>): T? {
return (if (isCommon) node.commonDeclaration() else node.targetDeclarations[targetIndex]) as T?
}
@@ -1,134 +0,0 @@
/*
* 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.metadata
import kotlinx.metadata.*
import kotlinx.metadata.klib.KlibModuleMetadata
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
import org.jetbrains.kotlin.descriptors.commonizer.cir.*
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
import org.jetbrains.kotlin.utils.addToStdlib.cast
// TODO: add logging
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
internal object MetadataBuilder {
fun build(node: CirRootNode, targetIndex: Int): Pair<CommonizerTarget, Collection<KlibModuleMetadata>> =
node.accept(MetadataBuildingVisitor(), VisitingContext.newContext(node, targetIndex)).cast()
private class MetadataBuildingVisitor : CirNodeVisitor<VisitingContext, Any?> {
private val classConsumer = ClassConsumer()
override fun visitRootNode(node: CirRootNode, context: VisitingContext): Pair<CommonizerTarget, Collection<KlibModuleMetadata>> {
val modules: Collection<KlibModuleMetadata> = buildMembers(context, node.modules)
return context.target to modules
}
override fun visitModuleNode(node: CirModuleNode, context: VisitingContext): KlibModuleMetadata? {
val cirModule = context.get<CirModule>(node) ?: return null
val fragments: MutableCollection<KmModuleFragment> = mutableListOf()
buildMembers(context, node.packages, destination = fragments)
addEmptyFragments(fragments)
return cirModule.buildModule(fragments)
}
override fun visitPackageNode(node: CirPackageNode, context: VisitingContext): KmModuleFragment? {
val cirPackage = context.get<CirPackage>(node) ?: return null
try {
buildMembers(context, node.classes, callback = classConsumer::consumeAll)
val topLevelTypeAliases = mutableListOf<KmTypeAlias>()
node.typeAliases.values.forEach { typeAliasNode ->
when (val classifier = typeAliasNode.accept(this, context)) {
null -> Unit
is KmClass -> classConsumer.consume(classifier)
is KmTypeAlias -> topLevelTypeAliases += classifier
else -> error("Unexpected classifier: ${classifier::class.java}, $classifier")
}
}
linkSealedClassesWithSubclasses(node.fqName, classConsumer)
val topLevelFunctions: Collection<KmFunction> = buildMembers(context, node.functions)
val topLevelProperties: Collection<KmProperty> = buildMembers(context, node.properties)
return cirPackage.buildModuleFragment(classConsumer.allClasses, topLevelTypeAliases, topLevelFunctions, topLevelProperties)
} finally {
// Important: clean-up class consumer every time when leaving package
classConsumer.reset()
}
}
override fun visitPropertyNode(node: CirPropertyNode, context: VisitingContext): KmProperty? {
return context.get<CirProperty>(node)?.buildProperty(context)
}
override fun visitFunctionNode(node: CirFunctionNode, context: VisitingContext): KmFunction? {
return context.get<CirFunction>(node)?.buildFunction(context)
}
override fun visitClassNode(node: CirClassNode, context: VisitingContext): KmClass? {
val cirClass = context.get<CirClass>(node) ?: return null
@Suppress("NAME_SHADOWING") val context = if (cirClass.isInner) context else context.topLevelContext
val classContext = context.childContext(cirClass)
val directNestedClasses = buildMembers(context = classContext, node.classes, callback = classConsumer::consumeAll)
val nestedConstructors: Collection<KmConstructor> = buildMembers(context = classContext, node.constructors)
val nestedFunctions: Collection<KmFunction> = buildMembers(context = classContext, node.functions)
val nestedProperties: Collection<KmProperty> = buildMembers(context = classContext, node.properties)
val className = node.classId.asString()
return cirClass.buildClass(context, className, directNestedClasses, nestedConstructors, nestedFunctions, nestedProperties)
}
override fun visitClassConstructorNode(node: CirClassConstructorNode, context: VisitingContext): KmConstructor? {
return context.get<CirClassConstructor>(node)?.buildClassConstructor(context)
}
override fun visitTypeAliasNode(node: CirTypeAliasNode, context: VisitingContext): Any? {
val cirClassifier = context.get<CirClassifier>(node) ?: return null
val className = node.classId.asString()
return when (cirClassifier) {
is CirTypeAlias -> cirClassifier.buildTypeAlias(context)
is CirClass -> cirClassifier.buildClass(context, className, emptyList(), emptyList(), emptyList(), emptyList())
else -> error("Unexpected CIR classifier: ${cirClassifier::class.java}, $cirClassifier")
}
}
private inline fun <reified N : CirNode<*, *>, reified M : Any> buildMembers(
context: VisitingContext,
cirMembersNodes: Map<*, N>,
destination: MutableCollection<M> = mutableListOf(),
callback: (Collection<M>) -> Unit = {}
): Collection<M> {
return cirMembersNodes.values.mapNotNullTo(destination) { it.accept(this, context) as M? }.also(callback)
}
}
}
internal class ClassConsumer {
private val _allClasses = mutableListOf<KmClass>()
private val _sealedClasses = mutableListOf<KmClass>()
val allClasses: Collection<KmClass> get() = _allClasses
val sealedClasses: Collection<KmClass> get() = _sealedClasses
fun consume(clazz: KmClass) {
_allClasses += clazz
if (Flag.Common.IS_SEALED(clazz.flags)) _sealedClasses += clazz
}
fun consumeAll(classes: Collection<KmClass>) = classes.forEach(::consume)
fun reset() {
_allClasses.clear()
_sealedClasses.clear()
}
}
@@ -5,36 +5,34 @@
package org.jetbrains.kotlin.descriptors.commonizer.stats package org.jetbrains.kotlin.descriptors.commonizer.stats
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.stats.AggregatedStatsCollector.AggregatedStatsRow
import org.jetbrains.kotlin.descriptors.commonizer.stats.RawStatsCollector.CommonDeclarationStatus.* import org.jetbrains.kotlin.descriptors.commonizer.stats.RawStatsCollector.CommonDeclarationStatus.*
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
class AggregatedStatsCollector( class AggregatedStatsCollector(
targets: List<KonanTarget>, targets: List<KonanTarget>
private val output: StatsOutput
) : StatsCollector { ) : StatsCollector {
private val aggregatingOutput = AggregatingOutput() private val wrappedCollector = RawStatsCollector(targets)
private val wrappedCollector = RawStatsCollector(targets, aggregatingOutput)
override fun logStats(result: List<DeclarationDescriptor?>) { override fun logDeclaration(targetIndex: Int, lazyStatsKey: () -> StatsCollector.StatsKey) {
wrappedCollector.logStats(result) wrappedCollector.logDeclaration(targetIndex, lazyStatsKey)
} }
override fun close() { override fun writeTo(statsOutput: StatsOutput) {
output.writeHeader(AggregatedStatsHeader) val aggregatingOutput = AggregatingOutput()
wrappedCollector.writeTo(aggregatingOutput)
aggregatingOutput.aggregatedStats.keys.sortedBy { it }.forEach { key -> statsOutput.use {
val row = aggregatingOutput.aggregatedStats.getValue(key) statsOutput.writeHeader(AggregatedStatsHeader)
output.writeRow(row)
aggregatingOutput.aggregatedStats.keys.sortedBy { it }.forEach { key ->
val row = aggregatingOutput.aggregatedStats.getValue(key)
statsOutput.writeRow(row)
}
} }
output.close()
wrappedCollector.close()
} }
object AggregatedStatsHeader : StatsOutput.StatsHeader { object AggregatedStatsHeader : StatsOutput.StatsHeader {
private val headerItems = listOf( override fun toList(): List<String> = listOf(
"Declaration Type", "Declaration Type",
"Lifted Up", "Lifted Up",
"Lifted Up, %%", "Lifted Up, %%",
@@ -46,11 +44,9 @@ class AggregatedStatsCollector(
"Failed: Other, %%", "Failed: Other, %%",
"Total" "Total"
) )
override fun toList(): List<String> = headerItems
} }
class AggregatedStatsRow( private class AggregatedStatsRow(
private val declarationType: DeclarationType private val declarationType: DeclarationType
) : StatsOutput.StatsRow { ) : StatsOutput.StatsRow {
var liftedUp: Int = 0 var liftedUp: Int = 0
@@ -78,33 +74,32 @@ class AggregatedStatsCollector(
} }
} }
} private class AggregatingOutput : StatsOutput {
val aggregatedStats = HashMap<DeclarationType, AggregatedStatsRow>()
@Suppress("MoveVariableDeclarationIntoWhen") override fun writeHeader(header: StatsOutput.StatsHeader) {
private class AggregatingOutput : StatsOutput { check(header is RawStatsCollector.RawStatsHeader)
val aggregatedStats = HashMap<DeclarationType, AggregatedStatsRow>() // do nothing
}
override fun writeHeader(header: StatsOutput.StatsHeader) { override fun writeRow(row: StatsOutput.StatsRow) {
check(header is RawStatsCollector.RawStatsHeader) check(row is RawStatsCollector.RawStatsRow)
// do nothing
}
override fun writeRow(row: StatsOutput.StatsRow) { val declarationType = row.statsKey.declarationType
check(row is RawStatsCollector.RawStatsRow) val aggregatedStatsRow = aggregatedStats.getOrPut(declarationType) { AggregatedStatsRow(declarationType) }
when (row.common) {
val aggregatedStatsRow = aggregatedStats.getOrPut(row.declarationType) { AggregatedStatsRow(row.declarationType) } LIFTED_UP -> aggregatedStatsRow.liftedUp++
when (row.common) { EXPECT -> aggregatedStatsRow.successfullyCommonized++
LIFTED_UP -> aggregatedStatsRow.liftedUp++ MISSING -> {
EXPECT -> aggregatedStatsRow.successfullyCommonized++ if (row.platform.any { it == RawStatsCollector.PlatformDeclarationStatus.MISSING }) {
MISSING -> { aggregatedStatsRow.failedBecauseMissing++
if (row.platform.any { it == RawStatsCollector.PlatformDeclarationStatus.MISSING }) { } else {
aggregatedStatsRow.failedBecauseMissing++ aggregatedStatsRow.failedOther++
} else { }
aggregatedStatsRow.failedOther++
} }
} }
} }
}
override fun close() = Unit override fun close() = Unit
}
} }
@@ -5,9 +5,6 @@
package org.jetbrains.kotlin.descriptors.commonizer.stats package org.jetbrains.kotlin.descriptors.commonizer.stats
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
enum class DeclarationType(val alias: String) { enum class DeclarationType(val alias: String) {
TOP_LEVEL_CONST_VAL("TOP-LEVEL CONST-VAL"), TOP_LEVEL_CONST_VAL("TOP-LEVEL CONST-VAL"),
TOP_LEVEL_VAL("TOP-LEVEL VAL"), TOP_LEVEL_VAL("TOP-LEVEL VAL"),
@@ -23,30 +20,5 @@ enum class DeclarationType(val alias: String) {
TYPE_ALIAS("TYPE_ALIAS"), TYPE_ALIAS("TYPE_ALIAS"),
ENUM_ENTRY("ENUM_ENTRY"), ENUM_ENTRY("ENUM_ENTRY"),
ENUM_CLASS("ENUM_CLASS"), ENUM_CLASS("ENUM_CLASS"),
MODULE("MODULE"), MODULE("MODULE")
UNKNOWN("UNKNOWN");
companion object {
val DeclarationDescriptor.declarationType: DeclarationType
get() = when (this) {
is ClassDescriptor -> {
if (isCompanionObject) {
COMPANION_OBJECT
} else when (kind) {
ClassKind.ENUM_CLASS -> ENUM_CLASS
ClassKind.ENUM_ENTRY -> ENUM_ENTRY
ClassKind.INTERFACE -> if (DescriptorUtils.isTopLevelDeclaration(this)) TOP_LEVEL_INTERFACE else NESTED_INTERFACE
else -> if (DescriptorUtils.isTopLevelDeclaration(this)) TOP_LEVEL_CLASS else NESTED_CLASS
}
}
is TypeAliasDescriptor -> TYPE_ALIAS
is ClassConstructorDescriptor -> CLASS_CONSTRUCTOR
is FunctionDescriptor -> if (DescriptorUtils.isTopLevelDeclaration(this)) TOP_LEVEL_FUN else NESTED_FUN
is PropertyDescriptor -> if (DescriptorUtils.isTopLevelDeclaration(this)) {
if (isConst) TOP_LEVEL_CONST_VAL else TOP_LEVEL_VAL
} else NESTED_VAL
is ModuleDescriptor -> MODULE
else -> UNKNOWN
}
}
} }
@@ -5,19 +5,21 @@
package org.jetbrains.kotlin.descriptors.commonizer.stats package org.jetbrains.kotlin.descriptors.commonizer.stats
import com.intellij.util.containers.FactoryMap
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.stats.DeclarationType.Companion.declarationType import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector.StatsKey
import org.jetbrains.kotlin.descriptors.commonizer.utils.firstNonNull import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsOutput.StatsHeader
import org.jetbrains.kotlin.descriptors.commonizer.utils.signature import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsOutput.StatsRow
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import java.util.*
import kotlin.collections.ArrayList
/** /**
* Allows printing commonization statistics to the file system. * Allows printing commonization statistics to the file system.
* *
* Output format is defined in [RawStatsCollector.output]. * Output format is defined in [StatsOutput].
* *
* Header row: "FQ Name, Extension Receiver, Parameter Names, Parameter Types, Declaration Type, common, <platform1>, <platform2> [<platformN>...]" * Header row: "ID, Extension Receiver, Parameter Names, Parameter Types, Declaration Type, common, <platform1>, <platform2> [<platformN>...]"
* *
* Possible values for "Declaration Type": * Possible values for "Declaration Type":
* - MODULE * - MODULE
@@ -44,113 +46,109 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
* *
* Example of output: * Example of output:
FQ Name|Extension Receiver|Parameter Names|Parameter Types|Declaration Type|common|macos_x64|ios_x64 ID|Extension Receiver|Parameter Names|Parameter Types|Declaration Type|common|macos_x64|ios_x64
<SystemConfiguration>||||MODULE|E|A|A SystemConfiguration||||MODULE|E|A|A
platform.SystemConfiguration.SCPreferencesContext||||CLASS|E|A|A platform/SystemConfiguration/SCPreferencesContext||||CLASS|E|A|A
platform.SystemConfiguration.SCPreferencesContext.Companion||||COMPANION_OBJECT|E|A|A platform/SystemConfiguration/SCPreferencesContext.Companion||||COMPANION_OBJECT|E|A|A
platform.SystemConfiguration.SCNetworkConnectionContext||||CLASS|E|A|A platform/SystemConfiguration/SCNetworkConnectionContext||||CLASS|E|A|A
platform.SystemConfiguration.SCNetworkConnectionContext.Companion||||COMPANION_OBJECT|E|A|A platform/SystemConfiguration/SCNetworkConnectionContext.Companion||||COMPANION_OBJECT|E|A|A
platform.SystemConfiguration.SCDynamicStoreRefVar||||TYPE_ALIAS|-|O|O platform/SystemConfiguration/SCDynamicStoreRefVar||||TYPE_ALIAS|-|O|O
platform.SystemConfiguration.SCVLANInterfaceRef||||TYPE_ALIAS|-|O|O platform/SystemConfiguration/SCVLANInterfaceRef||||TYPE_ALIAS|-|O|O
*/ */
class RawStatsCollector( class RawStatsCollector(private val targets: List<KonanTarget>) : StatsCollector {
private val targets: List<KonanTarget>, private inline val dimension get() = targets.size + 1
private val output: StatsOutput private inline val targetNames get() = targets.map { it.name }
) : StatsCollector {
private var headerWritten = false
override fun logStats(result: List<DeclarationDescriptor?>) { private inline val indexOfCommon get() = targets.size
if (!headerWritten) { private inline val platformDeclarationsCount get() = targets.size
writeHeader()
headerWritten = true
}
val firstNotNull = result.firstNonNull() private val stats = FactoryMap.create<StatsKey, StatsValue> { StatsValue(dimension) }
val lastIsNull = result.last() == null
val statsRow = RawStatsRow( override fun logDeclaration(targetIndex: Int, lazyStatsKey: () -> StatsKey) {
dimension = targets.size, stats.getValue(lazyStatsKey())[targetIndex] = true
fqName = if (firstNotNull is ModuleDescriptor) firstNotNull.name.asString() else firstNotNull.fqNameSafe.asString(), }
declarationType = firstNotNull.declarationType
)
// extension receiver override fun writeTo(statsOutput: StatsOutput) {
if (firstNotNull is PropertyDescriptor || firstNotNull is SimpleFunctionDescriptor) { val mergedStats = stats.filterTo(mutableMapOf()) { (statsKey, _) ->
statsRow.extensionReceiver = when (statsKey.declarationType) {
(firstNotNull as CallableDescriptor).extensionReceiverParameter?.type?.signature.orEmpty() DeclarationType.TOP_LEVEL_CLASS, DeclarationType.TOP_LEVEL_INTERFACE -> false
} else -> true
if (firstNotNull is ConstructorDescriptor || firstNotNull is SimpleFunctionDescriptor) {
val functionDescriptor = (firstNotNull as FunctionDescriptor)
// parameter names
statsRow.parameterNames = functionDescriptor.valueParameters.joinToString { it.name.asString() }
// parameter types
statsRow.parameterTypes = functionDescriptor.valueParameters.joinToString { it.type.signature }
}
var isLiftedUp = !lastIsNull
for (index in 0 until result.size - 1) {
statsRow.platform += when {
result[index] == null -> PlatformDeclarationStatus.MISSING
lastIsNull -> PlatformDeclarationStatus.ORIGINAL
else -> {
isLiftedUp = false
PlatformDeclarationStatus.ACTUAL
}
} }
} }
statsRow.common = when { stats.forEach { (statsKey, statsValue) ->
isLiftedUp -> CommonDeclarationStatus.LIFTED_UP when (statsKey.declarationType) {
lastIsNull -> CommonDeclarationStatus.MISSING DeclarationType.TOP_LEVEL_CLASS, DeclarationType.TOP_LEVEL_INTERFACE -> {
else -> CommonDeclarationStatus.EXPECT if (statsValue[indexOfCommon]) {
val alternativeKey = statsKey.copy(declarationType = DeclarationType.TYPE_ALIAS)
val alternativeValue = mergedStats[alternativeKey]
if (alternativeValue != null && !alternativeValue[indexOfCommon]) {
alternativeValue[indexOfCommon] = true
return@forEach
}
}
mergedStats[statsKey] = statsValue
}
else -> Unit
}
} }
output.writeRow(statsRow) statsOutput.use {
} statsOutput.writeHeader(RawStatsHeader(targetNames))
override fun close() { mergedStats.forEach { (statsKey, statsValue) ->
output.close() val commonIsMissing = !statsValue[indexOfCommon]
}
private fun writeHeader() { var isLiftedUp = !commonIsMissing
output.writeHeader(RawStatsHeader(targets.map { it.name })) val platform = ArrayList<PlatformDeclarationStatus>(platformDeclarationsCount)
}
class RawStatsHeader( for (index in 0 until platformDeclarationsCount) {
private val targetNames: List<String> platform += when {
) : StatsOutput.StatsHeader { !statsValue[index] -> PlatformDeclarationStatus.MISSING
override fun toList(): List<String> = mutableListOf<String>().apply { commonIsMissing -> PlatformDeclarationStatus.ORIGINAL
this += "FQ Name" else -> {
this += "Extension Receiver" isLiftedUp = false
this += "Parameter Names" PlatformDeclarationStatus.ACTUAL
this += "Parameter Types" }
this += "Declaration Type" }
this += "common" }
this += targetNames
val common = when {
isLiftedUp -> CommonDeclarationStatus.LIFTED_UP
commonIsMissing -> CommonDeclarationStatus.MISSING
else -> CommonDeclarationStatus.EXPECT
}
statsOutput.writeRow(RawStatsRow(statsKey, common, platform))
}
} }
} }
class RawStatsHeader(private val targetNames: List<String>) : StatsHeader {
override fun toList() =
listOf("ID", "Extension Receiver", "Parameter Names", "Parameter Types", "Declaration Type", "common") + targetNames
}
class RawStatsRow( class RawStatsRow(
dimension: Int, val statsKey: StatsKey,
val fqName: String, val common: CommonDeclarationStatus,
val declarationType: DeclarationType val platform: List<PlatformDeclarationStatus>
) : StatsOutput.StatsRow { ) : StatsRow {
var extensionReceiver: String = "" override fun toList(): List<String> {
var parameterNames: String = "" val result = mutableListOf(
var parameterTypes: String = "" statsKey.id,
lateinit var common: CommonDeclarationStatus statsKey.extensionReceiver.orEmpty(),
val platform: MutableList<PlatformDeclarationStatus> = ArrayList(dimension) statsKey.parameterNames.joinToString(),
statsKey.parameterTypes.joinToString(),
statsKey.declarationType.alias,
common.alias.toString()
)
override fun toList(): List<String> = mutableListOf<String>().apply { platform.mapTo(result) { it.alias.toString() }
this += fqName
this += extensionReceiver return result
this += parameterNames
this += parameterTypes
this += declarationType.alias
this += common.alias.toString()
platform.forEach { this += it.alias.toString() }
} }
} }
@@ -166,3 +164,5 @@ class RawStatsCollector(
MISSING('-') MISSING('-')
} }
} }
private typealias StatsValue = BitSet
@@ -5,9 +5,17 @@
package org.jetbrains.kotlin.descriptors.commonizer.stats package org.jetbrains.kotlin.descriptors.commonizer.stats
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor interface StatsCollector {
import java.io.Closeable data class StatsKey(
val id: String,
val extensionReceiver: String?,
val parameterNames: List<String>,
val parameterTypes: List<String>,
val declarationType: DeclarationType
) {
constructor(id: String, declarationType: DeclarationType) : this(id, null, emptyList(), emptyList(), declarationType)
}
interface StatsCollector : Closeable { fun logDeclaration(targetIndex: Int, lazyStatsKey: () -> StatsKey)
fun logStats(result: List<DeclarationDescriptor?>) fun writeTo(statsOutput: StatsOutput)
} }
@@ -44,6 +44,9 @@ private val OBJC_INTEROP_CALLABLE_ANNOTATIONS = listOf(
"ObjCFactory" "ObjCFactory"
) )
internal val DEFAULT_CONSTRUCTOR_NAME = Name.identifier("<init>").intern()
internal val DEFAULT_SETTER_VALUE_NAME = Name.identifier("value").intern()
internal fun Name.strip(): String = internal fun Name.strip(): String =
asString().removeSurrounding("<", ">") asString().removeSurrounding("<", ">")
@@ -58,6 +58,9 @@ private fun StringBuilder.buildTypeSignature(type: KotlinType, exploredTypeParam
} }
append("]") append("]")
} }
if (type.isMarkedNullable)
append("?")
} else { } else {
// N.B. this is classifier type // N.B. this is classifier type
val abbreviation = (type as? AbbreviatedType)?.abbreviation ?: type val abbreviation = (type as? AbbreviatedType)?.abbreviation ?: type
@@ -81,10 +84,10 @@ private fun StringBuilder.buildTypeSignature(type: KotlinType, exploredTypeParam
} }
append(">") append(">")
} }
}
if (type.isMarkedNullable) if (abbreviation.isMarkedNullable)
append("?") append("?")
}
} }
// dedicated to hold unique entries of "signature" // dedicated to hold unique entries of "signature"