From b29fd17d26b340992d072a0272bb1167fd51ffc9 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Thu, 1 Jul 2021 17:01:05 +0200 Subject: [PATCH] [Commonizer] Use `AssociativeCommonizer` signature to implement ClassOrTypeAliasTypeCommonizer This drastically improves performance for now, since the previous Adapter implementation was at least O(n^2). While the Adapter implementation could have been reduced to O(n), the Signature of StatelessCommonizer was misleading. StatelessCommonizer will be introduced back later when other Commonizer implementations are ready to be converted to a new Signature. --- .../commonizer/core/AssociativeCommonizer.kt | 35 ++++++++++++ .../core/ClassOrTypeAliasTypeCommonizer.kt | 55 +++++++++---------- .../kotlin/commonizer/core/Commonizer.kt | 5 -- .../commonizer/core/StatelessCommonizer.kt | 31 ----------- 4 files changed, 61 insertions(+), 65 deletions(-) create mode 100644 native/commonizer/src/org/jetbrains/kotlin/commonizer/core/AssociativeCommonizer.kt delete mode 100644 native/commonizer/src/org/jetbrains/kotlin/commonizer/core/StatelessCommonizer.kt diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/AssociativeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/AssociativeCommonizer.kt new file mode 100644 index 00000000000..9bb4f4bda59 --- /dev/null +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/AssociativeCommonizer.kt @@ -0,0 +1,35 @@ +/* + * 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.core + +internal interface AssociativeCommonizer { + fun commonize(first: T, second: T): T? +} + +internal open class AssociativeCommonizerAdapter( + private val commonizer: AssociativeCommonizer +) : AbstractStandardCommonizer() { + + private var _result: T? = null + + override fun commonizationResult(): T { + return _result ?: failInEmptyState() + } + + override fun initialize(first: T) = Unit + + override fun doCommonizeWith(next: T): Boolean { + val currentResult = _result + + if (currentResult == null) { + _result = next + return true + } + + _result = commonizer.commonize(currentResult, next) + return _result != null + } +} \ No newline at end of file diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt index 2329cd376ca..11c18a78e51 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/ClassOrTypeAliasTypeCommonizer.kt @@ -10,52 +10,49 @@ import org.jetbrains.kotlin.commonizer.cir.CirClassType import org.jetbrains.kotlin.commonizer.cir.CirTypeAliasType import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers -internal class ClassOrTypeAliasTypeStatelessCommonizer( +internal class ClassOrTypeAliasTypeAssociativeCommonizer( private val classifiers: CirKnownClassifiers -) : StatelessCommonizer { +) : AssociativeCommonizer { - override fun commonize(values: List): CirClassOrTypeAliasType? { - if (values.isEmpty()) return null - values.singleOrNull()?.let { return it } - - val classTypes = values.filterIsInstance() - val typeAliasTypes = values.filterIsInstance() - val expandedTypeAliasTypes = typeAliasTypes.map { it.expandedType() } - - if (values.all { it is CirClassType }) { - return ClassTypeCommonizer(classifiers).commonize(classTypes) + override fun commonize(first: CirClassOrTypeAliasType, second: CirClassOrTypeAliasType): CirClassOrTypeAliasType? { + if (first is CirClassType && second is CirClassType) { + return ClassTypeCommonizer(classifiers).commonize(listOf(first, second)) } - if (values.all { it is CirTypeAliasType }) { + if (first is CirTypeAliasType && second is CirTypeAliasType) { /* In case regular type-alias-type commonization fails, we try to expand all type-aliases and try our luck with commonizing those class types */ - return TypeAliasTypeCommonizer(classifiers).commonize(typeAliasTypes) - ?: ClassTypeCommonizer(classifiers).commonize(expandedTypeAliasTypes) + return TypeAliasTypeCommonizer(classifiers).commonize(listOf(first, second)) + ?: ClassTypeCommonizer(classifiers).commonize(listOf(first.expandedType(), second.expandedType())) + } + + val classType = when { + first is CirClassType -> first + second is CirClassType -> second + else -> return null + } + + val typeAliasType = when { + first is CirTypeAliasType -> first + second is CirTypeAliasType -> second + else -> return null } /* - There are type-alias types & class types enqueued for commonization. - We reduce all classes to a common representation and all type aliases to a common representation. + TypeAliasCommonizer will be able to figure out if the typealias will be represented as expect class in common. + If so, re-use this class type, otherwise: try to expand the typeAlias */ - val commonizedClass = ClassTypeCommonizer(classifiers).commonize(classTypes) ?: return null - val commonizedTypeAlias = TypeAliasTypeCommonizer(classifiers).commonize(typeAliasTypes) + val typeAliasClassType = TypeAliasTypeCommonizer(classifiers).commonize(listOf(typeAliasType))?.expandedType() + ?: typeAliasType.expandedType() - if (commonizedTypeAlias != null) { - return ClassTypeCommonizer(classifiers).commonize(listOf(commonizedClass, commonizedTypeAlias.expandedType())) - } - - /* - If type-alias type commonization failed: - Last attempt: Try to commonize all type-alias expansions with the commonized class - */ - return ClassTypeCommonizer(classifiers).commonize(expandedTypeAliasTypes + commonizedClass) + return ClassTypeCommonizer(classifiers).commonize(listOf(classType, typeAliasClassType)) } } internal class ClassOrTypeAliasTypeCommonizer(classifiers: CirKnownClassifiers) : - StatelessCommonizerAdapter(ClassOrTypeAliasTypeStatelessCommonizer(classifiers)) + AssociativeCommonizerAdapter(ClassOrTypeAliasTypeAssociativeCommonizer(classifiers)) internal tailrec fun CirClassOrTypeAliasType.expandedType(): CirClassType = when (this) { is CirClassType -> this diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/Commonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/Commonizer.kt index 4cac2958606..656cdf3ce02 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/Commonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/Commonizer.kt @@ -11,11 +11,6 @@ interface Commonizer { } fun Commonizer.commonize(values: List): R? { - /* Fast path: If commonizer supports StatelessCommonizer interface */ - if (this is StatelessCommonizerAdapter) { - return commonize(values) - } - values.forEach { value -> if (!commonizeWith(value)) return null } return result } diff --git a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/StatelessCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/StatelessCommonizer.kt deleted file mode 100644 index 2d2530ecda5..00000000000 --- a/native/commonizer/src/org/jetbrains/kotlin/commonizer/core/StatelessCommonizer.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.core - -interface StatelessCommonizer { - fun commonize(values: List): R? -} - -open class StatelessCommonizerAdapter( - private val commonizer: StatelessCommonizer -) : AbstractStandardCommonizer(), StatelessCommonizer by commonizer { - private val values = mutableListOf() - - override fun commonizationResult(): R { - try { - return checkNotNull(commonize(values.toList())) - } finally { - values.clear() - } - } - - override fun initialize(first: T) = Unit - - override fun doCommonizeWith(next: T): Boolean { - values.add(next) - return commonize(values.toList()) != null - } -}