[Commonzer] Fix ISE during commonization, improve interner performance

Issue #MMPP-191
This commit is contained in:
Dmitriy Dolovov
2020-03-06 12:44:38 +07:00
parent 7da220b0a2
commit ed96b81a42
8 changed files with 75 additions and 79 deletions
+1
View File
@@ -20,6 +20,7 @@ dependencies {
compileOnly(project(":compiler:frontend")) compileOnly(project(":compiler:frontend"))
compileOnly(project(":native:frontend.native")) compileOnly(project(":native:frontend.native"))
compileOnly(project(":kotlin-util-klib-metadata")) compileOnly(project(":kotlin-util-klib-metadata"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
// This dependency is necessary to keep the right dependency record inside of POM file: // This dependency is necessary to keep the right dependency record inside of POM file:
mavenCompileScope(project(":kotlin-compiler")) mavenCompileScope(project(":kotlin-compiler"))
@@ -6,7 +6,9 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.utils.NonThreadSafeInterner import org.jetbrains.kotlin.descriptors.commonizer.utils.Interner
import org.jetbrains.kotlin.descriptors.commonizer.utils.appendHashCode
import org.jetbrains.kotlin.descriptors.commonizer.utils.hashCode
import org.jetbrains.kotlin.descriptors.commonizer.utils.intern import org.jetbrains.kotlin.descriptors.commonizer.utils.intern
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -25,7 +27,7 @@ class CirAnnotation private constructor(original: AnnotationDescriptor) {
// See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode // See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode
private var cachedHashCode = 0 private var cachedHashCode = 0
private fun computeHashCode() = fqName.hashCode() * 31 + allValueArguments.hashCode() private fun computeHashCode() = hashCode(fqName).appendHashCode(allValueArguments)
override fun hashCode(): Int { override fun hashCode(): Int {
var currentHashCode = cachedHashCode var currentHashCode = cachedHashCode
@@ -36,14 +38,14 @@ class CirAnnotation private constructor(original: AnnotationDescriptor) {
return currentHashCode return currentHashCode
} }
override fun equals(other: Any?): Boolean = override fun equals(other: Any?): Boolean = when {
if (other is CirAnnotation) { other === this -> true
fqName == other.fqName && allValueArguments == other.allValueArguments other is CirAnnotation -> fqName == other.fqName && allValueArguments == other.allValueArguments
} else else -> false
false }
companion object { companion object {
private val interner = NonThreadSafeInterner<CirAnnotation>() private val interner = Interner<CirAnnotation>()
fun create(original: AnnotationDescriptor): CirAnnotation = interner.intern(CirAnnotation(original)) fun create(original: AnnotationDescriptor): CirAnnotation = interner.intern(CirAnnotation(original))
} }
@@ -6,7 +6,9 @@
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir package org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.commonizer.utils.NonThreadSafeInterner import org.jetbrains.kotlin.descriptors.commonizer.utils.Interner
import org.jetbrains.kotlin.descriptors.commonizer.utils.hashCode
import org.jetbrains.kotlin.descriptors.commonizer.utils.appendHashCode
import org.jetbrains.kotlin.descriptors.commonizer.utils.intern import org.jetbrains.kotlin.descriptors.commonizer.utils.intern
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -85,16 +87,13 @@ class CirValueParameterImpl private constructor(original: ValueParameterDescript
// See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode // See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode
private var cachedHashCode = 0 private var cachedHashCode = 0
private fun computeHashCode(): Int { private fun computeHashCode() = hashCode(name)
var result = name.hashCode() .appendHashCode(annotations)
result += 31 * result + annotations.hashCode() .appendHashCode(returnType)
result += 31 * result + returnType.hashCode() .appendHashCode(varargElementType)
result += 31 * result + varargElementType.hashCode() .appendHashCode(declaresDefaultValue)
result += 31 * result + declaresDefaultValue.hashCode() .appendHashCode(isCrossinline)
result += 31 * result + isCrossinline.hashCode() .appendHashCode(isNoinline)
result += 31 * result + isNoinline.hashCode()
return result
}
override fun hashCode(): Int { override fun hashCode(): Int {
var currentHashCode = cachedHashCode var currentHashCode = cachedHashCode
@@ -105,8 +104,9 @@ class CirValueParameterImpl private constructor(original: ValueParameterDescript
return currentHashCode return currentHashCode
} }
override fun equals(other: Any?): Boolean = override fun equals(other: Any?): Boolean = when {
if (other is CirValueParameterImpl) { other === this -> true
other is CirValueParameterImpl -> {
name == other.name name == other.name
&& returnType == other.returnType && returnType == other.returnType
&& annotations == other.annotations && annotations == other.annotations
@@ -114,11 +114,12 @@ class CirValueParameterImpl private constructor(original: ValueParameterDescript
&& declaresDefaultValue == other.declaresDefaultValue && declaresDefaultValue == other.declaresDefaultValue
&& isCrossinline == other.isCrossinline && isCrossinline == other.isCrossinline
&& isNoinline == other.isNoinline && isNoinline == other.isNoinline
} else }
false else -> false
}
companion object { companion object {
private val interner = NonThreadSafeInterner<CirValueParameterImpl>() private val interner = Interner<CirValueParameterImpl>()
fun create(original: ValueParameterDescriptor): CirValueParameterImpl = interner.intern(CirValueParameterImpl(original)) fun create(original: ValueParameterDescriptor): CirValueParameterImpl = interner.intern(CirValueParameterImpl(original))
} }
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirGetter.Companion.toGetter import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirGetter.Companion.toGetter
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirSetter.Companion.toSetter import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ir.CirSetter.Companion.toSetter
import org.jetbrains.kotlin.descriptors.commonizer.utils.NonThreadSafeInterner import org.jetbrains.kotlin.descriptors.commonizer.utils.Interner
import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValue
interface CirProperty : CirFunctionOrProperty { interface CirProperty : CirFunctionOrProperty {
@@ -78,7 +78,7 @@ data class CirGetter private constructor(
override val isInline: Boolean override val isInline: Boolean
) : CirPropertyAccessor { ) : CirPropertyAccessor {
companion object { companion object {
private val interner = NonThreadSafeInterner<CirGetter>() private val interner = Interner<CirGetter>()
val DEFAULT_NO_ANNOTATIONS = interner.intern( val DEFAULT_NO_ANNOTATIONS = interner.intern(
CirGetter( CirGetter(
@@ -114,7 +114,7 @@ data class CirSetter private constructor(
override val isInline: Boolean override val isInline: Boolean
) : CirPropertyAccessor, CirDeclarationWithVisibility { ) : CirPropertyAccessor, CirDeclarationWithVisibility {
companion object { companion object {
private val interner = NonThreadSafeInterner<CirSetter>() private val interner = Interner<CirSetter>()
fun createDefaultNoAnnotations(visibility: Visibility) = interner.intern( fun createDefaultNoAnnotations(visibility: Visibility) = interner.intern(
CirSetter( CirSetter(
@@ -60,54 +60,44 @@ class CirSimpleType private constructor(original: SimpleType) : CirType() {
inline val isClassOrTypeAlias get() = (kind == CLASS || kind == TYPE_ALIAS) inline val isClassOrTypeAlias get() = (kind == CLASS || kind == TYPE_ALIAS)
val fqNameWithTypeParameters = original.fqNameWithTypeParameters val fqNameWithTypeParameters = original.fqNameWithTypeParameters
// Note: equals() and hashCode() are implemented in a way that only right-hand side declaration override fun equals(other: Any?) = when {
// is compared for typealiases (well, actually "fqNameWithTypeParameters" for the right-hand side). other === this -> true
// This is sufficient for unit tests and for evaluating commonized supertypes, but is absolutely other is CirSimpleType -> {
// unsuitable for comparison of CirSimpleType for the purposes of interning, etc. isMarkedNullable == other.isMarkedNullable
override fun equals(other: Any?) = fqNameWithTypeParameters == (other as? CirSimpleType)?.fqNameWithTypeParameters && fqName == other.fqName
override fun hashCode() = fqNameWithTypeParameters.hashCode() && kind == other.kind
&& arguments == other.arguments
private class Interned(val type: CirSimpleType) { && fqNameWithTypeParameters == other.fqNameWithTypeParameters
// See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode && annotations == other.annotations
private var cachedHashCode = 0 && isDefinitelyNotNullType == other.isDefinitelyNotNullType
private fun computeHashCode(): Int {
var result = type.annotations.hashCode()
result = 31 * result + type.kind.hashCode()
result = 31 * result + type.fqName.hashCode()
result = 31 * result + type.arguments.hashCode()
result = 31 * result + type.isMarkedNullable.hashCode()
result = 31 * result + type.isDefinitelyNotNullType.hashCode()
result = 31 * result + type.fqNameWithTypeParameters.hashCode()
return result
} }
else -> false
}
override fun hashCode(): Int { // See also org.jetbrains.kotlin.types.KotlinType.cachedHashCode
var currentHashCode = cachedHashCode private var cachedHashCode = 0
if (currentHashCode != 0) return currentHashCode
currentHashCode = computeHashCode() private fun computeHashCode() = hashCode(annotations)
cachedHashCode = currentHashCode .appendHashCode(kind)
return currentHashCode .appendHashCode(fqName)
} .appendHashCode(arguments)
.appendHashCode(isMarkedNullable)
.appendHashCode(isDefinitelyNotNullType)
.appendHashCode(fqNameWithTypeParameters)
override fun equals(other: Any?): Boolean = override fun hashCode(): Int {
if (other is Interned) { var currentHashCode = cachedHashCode
type.isMarkedNullable == other.type.isMarkedNullable if (currentHashCode != 0) return currentHashCode
&& type.fqName == other.type.fqName
&& type.kind == other.type.kind currentHashCode = computeHashCode()
&& type.arguments == other.type.arguments cachedHashCode = currentHashCode
&& type.fqNameWithTypeParameters == other.type.fqNameWithTypeParameters return currentHashCode
&& type.annotations == other.type.annotations
&& type.isDefinitelyNotNullType == other.type.isDefinitelyNotNullType
} else
false
} }
companion object { companion object {
private val interner = NonThreadSafeInterner<Interned>() private val interner = Interner<CirSimpleType>()
fun create(original: SimpleType): CirSimpleType = interner.intern(Interned(CirSimpleType(original))).type fun create(original: SimpleType): CirSimpleType = interner.intern(CirSimpleType(original))
} }
} }
@@ -133,11 +123,7 @@ data class CirTypeConstructorId(val fqName: FqName, val numberOfTypeParameters:
constructor(type: SimpleType) : this(type.fqNameInterned, type.constructor.parameters.size) constructor(type: SimpleType) : this(type.fqNameInterned, type.constructor.parameters.size)
} }
data class CirTypeProjection( data class CirTypeProjection(val projectionKind: Variance, val isStarProjection: Boolean, val type: CirType) {
val projectionKind: Variance,
val isStarProjection: Boolean,
val type: CirType
) {
constructor(original: TypeProjection) : this(original.projectionKind, original.isStarProjection, CirType.create(original.type)) constructor(original: TypeProjection) : this(original.projectionKind, original.isStarProjection, CirType.create(original.type))
} }
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.descriptors.commonizer.utils package org.jetbrains.kotlin.descriptors.commonizer.utils
import java.util.WeakHashMap import com.intellij.util.containers.WeakInterner
internal class NonThreadSafeInterner<T : Any> { class Interner<T : Any> {
private val pool = WeakHashMap<T, T>() private val pool = WeakInterner<T>()
fun intern(value: T): T = pool.computeIfAbsent(value) { value } fun intern(value: T): T = pool.intern(value)
} }
@@ -16,3 +16,9 @@ internal fun <T> Sequence<T>.toList(expectedCapacity: Int): List<T> {
internal inline fun <reified T> Iterable<T?>.firstNonNull() = firstIsInstance<T>() internal inline fun <reified T> Iterable<T?>.firstNonNull() = firstIsInstance<T>()
internal fun Any?.isNull(): Boolean = this == null internal fun Any?.isNull(): Boolean = this == null
@Suppress("NOTHING_TO_INLINE")
inline fun hashCode(value: Any?): Int = value.hashCode()
@Suppress("NOTHING_TO_INLINE")
inline fun Int.appendHashCode(value: Any?): Int = 31 * this + hashCode(value)
@@ -74,7 +74,7 @@ private fun StringBuilder.buildFqNameWithTypeParameters(type: KotlinType, explor
} }
// dedicated to hold unique entries of "fqNameWithTypeParameters" // dedicated to hold unique entries of "fqNameWithTypeParameters"
private val stringInterner = NonThreadSafeInterner<String>() private val stringInterner = Interner<String>()
private val fqNameInterner = NonThreadSafeInterner<FqName>() private val fqNameInterner = Interner<FqName>()
private val nameInterner = NonThreadSafeInterner<Name>() private val nameInterner = Interner<Name>()