From cc4d93ac714dad984fcf787d14a1374079500a69 Mon Sep 17 00:00:00 2001 From: LepilkinaElena Date: Fri, 16 Oct 2020 21:07:04 +0300 Subject: [PATCH] [IR] Eliminated expensive calculating of fqNames (#3815) --- .../backend/common/CommonBackendContext.kt | 1 + .../lower/AbstractSuspendFunctionsLowering.kt | 3 +- .../kotlin/backend/jvm/JvmBackendContext.kt | 1 + .../kotlin/backend/wasm/WasmBackendContext.kt | 1 + .../kotlin/ir/types/irTypePredicates.kt | 159 +++++++++++++----- .../kotlin/ir/util/AdditionalIrUtils.kt | 14 +- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 2 +- 7 files changed, 132 insertions(+), 49 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt index 82bf0c46737..8ac18d2a9fe 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irString import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.util.IdSignature interface LoggingContext { var inVerbosePhase: Boolean diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/AbstractSuspendFunctionsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/AbstractSuspendFunctionsLowering.kt index b5ed5abd114..81fdbad7028 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/AbstractSuspendFunctionsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/AbstractSuspendFunctionsLowering.kt @@ -80,9 +80,10 @@ abstract class AbstractSuspendFunctionsLowering(val co // Suppress since it is used in native @Suppress("MemberVisibilityCanBePrivate") protected fun IrCall.isReturnIfSuspendedCall() = - symbol.owner.run { fqNameWhenAvailable == context.internalPackageFqn.child(Name.identifier("returnIfSuspended")) } + symbol.isPublicApi && context.ir.symbols.returnIfSuspended.signature == symbol.signature private fun tryTransformSuspendFunction(element: IrElement) = + if (element is IrSimpleFunction && element.isSuspend && element.modality != Modality.ABSTRACT) transformSuspendFunction(element, suspendLambdas[element]) else null diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index f529b4833b3..31f2605bdf8 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionReference import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi2ir.PsiErrorBuilder diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt index 8b297aec694..6e6d12b703a 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol +import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.name.FqName diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt index 7abb1ca2f51..081e4811541 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt @@ -5,20 +5,60 @@ package org.jetbrains.kotlin.ir.types +import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol +import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable +import org.jetbrains.kotlin.ir.util.hasEqualFqName +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.newHashMapWithExpectedSize -private fun IrType.isNotNullClassType(fqName: FqNameUnsafe) = isClassType(fqName, hasQuestionMark = false) -private fun IrType.isNullableClassType(fqName: FqNameUnsafe) = isClassType(fqName, hasQuestionMark = true) +@Suppress("ObjectPropertyName") +object IdSignatureValues { + @JvmField val any = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "Any") + @JvmField val nothing = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Nothing") + @JvmField val unit = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Unit") + @JvmField val _boolean = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "Boolean") + @JvmField val _char = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "Char") + @JvmField val _byte = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Byte") + @JvmField val _short = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Short") + @JvmField val _int = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Int") + @JvmField val _long = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Long") + @JvmField val _float = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Float") + @JvmField val _double = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Double") + @JvmField val number = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Number") + @JvmField val uByte = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"UByte") + @JvmField val uShort = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"UShort") + @JvmField val uInt = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"UInt") + @JvmField val uLong = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"ULong") + @JvmField val string = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"String") + @JvmField val array = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Array") + @JvmField val collection = getPublicSignature(StandardNames.COLLECTIONS_PACKAGE_FQ_NAME, "Collection") + @JvmField val kClass = getPublicSignature(StandardNames.KOTLIN_REFLECT_FQ_NAME, "KClass") + @JvmField val comparable = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"Comparable") + @JvmField val charSequence = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME,"CharSequence") + @JvmField val iterable = getPublicSignature(StandardNames.COLLECTIONS_PACKAGE_FQ_NAME, "Iterable") + @JvmField val continuation = getPublicSignature(StandardNames.COROUTINES_PACKAGE_FQ_NAME_RELEASE,"Continuation") + @JvmField val result = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "Result") + @JvmField val sequence = IdSignature.PublicSignature("kotlin.sequences", "Sequence", null, 0) +} -private fun IrType.isClassType(fqName: FqNameUnsafe, hasQuestionMark: Boolean? = null): Boolean { +private fun IrType.isNotNullClassType(signature: IdSignature.PublicSignature) = isClassType(signature, hasQuestionMark = false) +private fun IrType.isNullableClassType(signature: IdSignature.PublicSignature) = isClassType(signature, hasQuestionMark = true) + +fun getPublicSignature(packageFqName: FqName, name: String) = + IdSignature.PublicSignature(packageFqName.asString(), name, null, 0) + +private fun IrType.isClassType(signature: IdSignature.PublicSignature, hasQuestionMark: Boolean? = null): Boolean { if (this !is IrSimpleType) return false if (hasQuestionMark != null && this.hasQuestionMark != hasQuestionMark) return false - return classifier.isClassWithFqName(fqName) + if (!classifier.isPublicApi || !classifier.signature.isPublic) return false + return signature == classifier.signature } fun IrClassifierSymbol.isClassWithFqName(fqName: FqNameUnsafe): Boolean = @@ -29,55 +69,84 @@ private fun classFqNameEquals(symbol: IrClassSymbol, fqName: FqNameUnsafe): Bool return classFqNameEquals(symbol.owner, fqName) } +private val idSignatureToPrimitiveType: Map = + newHashMapWithExpectedSize(PrimitiveType.values().size).apply { + for (primitiveType in PrimitiveType.values()) { + this[getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, primitiveType.typeName.asString())] = primitiveType + } + } + +val primitiveArrayTypesSignatures: Map = + newHashMapWithExpectedSize(PrimitiveType.values().size).apply { + for (primitiveType in PrimitiveType.values()) { + this[primitiveType] = + getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "${primitiveType.typeName.asString()}Array") + } + } + private fun classFqNameEquals(declaration: IrClass, fqName: FqNameUnsafe): Boolean = - declaration.name == fqName.shortName() && fqName == declaration.fqNameWhenAvailable?.toUnsafe() + declaration.hasEqualFqName(fqName.toSafe()) -fun IrType.isAny(): Boolean = isNotNullClassType(StandardNames.FqNames.any) -fun IrType.isNullableAny(): Boolean = isNullableClassType(StandardNames.FqNames.any) +fun IrType.isAny(): Boolean = isNotNullClassType(IdSignatureValues.any) +fun IrType.isNullableAny(): Boolean = isNullableClassType(IdSignatureValues.any) -fun IrType.isString(): Boolean = isNotNullClassType(StandardNames.FqNames.string) -fun IrType.isNullableString(): Boolean = isNullableClassType(StandardNames.FqNames.string) -fun IrType.isStringClassType(): Boolean = isClassType(StandardNames.FqNames.string) -fun IrType.isArray(): Boolean = isNotNullClassType(StandardNames.FqNames.array) -fun IrType.isNullableArray(): Boolean = isNullableClassType(StandardNames.FqNames.array) -fun IrType.isCollection(): Boolean = isNotNullClassType(StandardNames.FqNames.collection.toUnsafe()) -fun IrType.isNothing(): Boolean = isNotNullClassType(StandardNames.FqNames.nothing) -fun IrType.isKClass(): Boolean = isNotNullClassType(StandardNames.FqNames.kClass) +fun IrType.isString(): Boolean = isNotNullClassType(IdSignatureValues.string) +fun IrType.isNullableString(): Boolean = isNullableClassType(IdSignatureValues.string) +fun IrType.isStringClassType(): Boolean = isClassType(IdSignatureValues.string) +fun IrType.isArray(): Boolean = isNotNullClassType(IdSignatureValues.array) +fun IrType.isNullableArray(): Boolean = isNullableClassType(IdSignatureValues.array) +fun IrType.isCollection(): Boolean = isNotNullClassType(IdSignatureValues.collection) +fun IrType.isNothing(): Boolean = isNotNullClassType(IdSignatureValues.nothing) -fun IrType.isPrimitiveType(): Boolean = StandardNames.FqNames.fqNameToPrimitiveType.keys.any { isNotNullClassType(it) } -fun IrType.isNullablePrimitiveType(): Boolean = StandardNames.FqNames.fqNameToPrimitiveType.keys.any { isNullableClassType(it) } +fun IrType.isPrimitiveType(hasQuestionMark: Boolean = false): Boolean = + (this is IrSimpleType && hasQuestionMark == this.hasQuestionMark) && + classOrNull?.takeIf(IrClassSymbol::isPublicApi)?.signature in idSignatureToPrimitiveType + +fun IrType.isNullablePrimitiveType(): Boolean = isPrimitiveType(true) fun IrType.isMarkedNullable() = (this as? IrSimpleType)?.hasQuestionMark ?: false -fun IrType.isUnit() = isNotNullClassType(StandardNames.FqNames.unit) +fun IrType.isUnit() = isNotNullClassType(IdSignatureValues.unit) -fun IrType.isBoolean(): Boolean = isNotNullClassType(StandardNames.FqNames._boolean) -fun IrType.isChar(): Boolean = isNotNullClassType(StandardNames.FqNames._char) -fun IrType.isByte(): Boolean = isNotNullClassType(StandardNames.FqNames._byte) -fun IrType.isShort(): Boolean = isNotNullClassType(StandardNames.FqNames._short) -fun IrType.isInt(): Boolean = isNotNullClassType(StandardNames.FqNames._int) -fun IrType.isLong(): Boolean = isNotNullClassType(StandardNames.FqNames._long) -fun IrType.isUByte(): Boolean = isNotNullClassType(StandardNames.FqNames.uByteFqName.toUnsafe()) -fun IrType.isUShort(): Boolean = isNotNullClassType(StandardNames.FqNames.uShortFqName.toUnsafe()) -fun IrType.isUInt(): Boolean = isNotNullClassType(StandardNames.FqNames.uIntFqName.toUnsafe()) -fun IrType.isULong(): Boolean = isNotNullClassType(StandardNames.FqNames.uLongFqName.toUnsafe()) -fun IrType.isFloat(): Boolean = isNotNullClassType(StandardNames.FqNames._float) -fun IrType.isDouble(): Boolean = isNotNullClassType(StandardNames.FqNames._double) -fun IrType.isNumber(): Boolean = isNotNullClassType(StandardNames.FqNames.number) +fun IrType.isBoolean(): Boolean = isNotNullClassType(IdSignatureValues._boolean) +fun IrType.isChar(): Boolean = isNotNullClassType(IdSignatureValues._char) +fun IrType.isByte(): Boolean = isNotNullClassType(IdSignatureValues._byte) +fun IrType.isShort(): Boolean = isNotNullClassType(IdSignatureValues._short) +fun IrType.isInt(): Boolean = isNotNullClassType(IdSignatureValues._int) +fun IrType.isLong(): Boolean = isNotNullClassType(IdSignatureValues._long) +fun IrType.isUByte(): Boolean = isNotNullClassType(IdSignatureValues.uByte) +fun IrType.isUShort(): Boolean = isNotNullClassType(IdSignatureValues.uShort) +fun IrType.isUInt(): Boolean = isNotNullClassType(IdSignatureValues.uInt) +fun IrType.isULong(): Boolean = isNotNullClassType(IdSignatureValues.uLong) +fun IrType.isFloat(): Boolean = isNotNullClassType(IdSignatureValues._float) +fun IrType.isDouble(): Boolean = isNotNullClassType(IdSignatureValues._double) +fun IrType.isNumber(): Boolean = isNotNullClassType(IdSignatureValues.number) -fun IrType.isComparable(): Boolean = isNotNullClassType(StandardNames.FqNames.comparable.toUnsafe()) -fun IrType.isCharSequence(): Boolean = isNotNullClassType(StandardNames.FqNames.charSequence) -fun IrType.isIterable(): Boolean = isNotNullClassType(StandardNames.FqNames.iterable.toUnsafe()) -fun IrType.isSequence(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.sequences.Sequence")) +fun IrType.isComparable(): Boolean = isNotNullClassType(IdSignatureValues.comparable) +fun IrType.isCharSequence(): Boolean = isNotNullClassType(IdSignatureValues.charSequence) +fun IrType.isIterable(): Boolean = isNotNullClassType(IdSignatureValues.iterable) +fun IrType.isSequence(): Boolean = isNotNullClassType(IdSignatureValues.sequence) -fun IrType.isBooleanArray(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.BooleanArray")) -fun IrType.isCharArray(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.CharArray")) -fun IrType.isByteArray(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.ByteArray")) -fun IrType.isShortArray(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.ShortArray")) -fun IrType.isIntArray(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.IntArray")) -fun IrType.isLongArray(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.LongArray")) -fun IrType.isFloatArray(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.FloatArray")) -fun IrType.isDoubleArray(): Boolean = isNotNullClassType(FqNameUnsafe("kotlin.DoubleArray")) +fun IrType.isBooleanArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.BOOLEAN]!!) +fun IrType.isCharArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.CHAR]!!) +fun IrType.isByteArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.BYTE]!!) +fun IrType.isShortArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.SHORT]!!) +fun IrType.isIntArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.INT]!!) +fun IrType.isLongArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.LONG]!!) +fun IrType.isFloatArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.FLOAT]!!) +fun IrType.isDoubleArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.DOUBLE]!!) -fun IrType.isKotlinResult(): Boolean = isNotNullClassType(StandardNames.RESULT_FQ_NAME.toUnsafe()) -fun IrType.isNullableContinuation(): Boolean = isNullableClassType(StandardNames.CONTINUATION_INTERFACE_FQ_NAME_RELEASE.toUnsafe()) +// TODO: remove this method using FqNames. +// Need to refactor declarationBuilders.kt: visibilty is known, need to add info about package in IrFactory.buildClass (similar to name). +fun IrType.isClassType(fqName: FqNameUnsafe, hasQuestionMark: Boolean): Boolean { + if (this !is IrSimpleType) return false + if (this.hasQuestionMark != hasQuestionMark) return false + return classifier.isClassWithFqName(fqName) +} + +fun IrType.isKotlinResult(): Boolean = isClassType(StandardNames.RESULT_FQ_NAME.toUnsafe(), false) + +fun IrType.isNullableContinuation(): Boolean = isClassType(StandardNames.CONTINUATION_INTERFACE_FQ_NAME_RELEASE.toUnsafe(), true) + +// FIR and backend instances have different mask. +fun IrType.isKClass(): Boolean = isClassType(StandardNames.FqNames.kClass, false) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt index 90120bbcd38..92a6fcf45c9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt @@ -85,11 +85,21 @@ fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean { private val IrConstructorCall.annotationClass get() = this.symbol.owner.constructedClass +val IrClass.packageFqName: FqName? + get() = if (symbol.isPublicApi) symbol.signature.packageFqName() else parent.getPackageFragment()?.fqName + +fun IrDeclarationWithName.hasEqualFqName(fqName: FqName): Boolean = + name == fqName.shortName() && when (val parent = parent) { + is IrPackageFragment -> parent.fqName == fqName.parent() + is IrDeclarationWithName -> parent.hasEqualFqName(fqName.parent()) + else -> false + } + fun List.hasAnnotation(fqName: FqName): Boolean = - any { it.annotationClass.fqNameWhenAvailable == fqName } + any { it.annotationClass.hasEqualFqName(fqName) } fun List.findAnnotation(fqName: FqName): IrConstructorCall? = - firstOrNull { it.annotationClass.fqNameWhenAvailable == fqName } + firstOrNull { it.annotationClass.hasEqualFqName(fqName) } val IrDeclaration.fileEntry: SourceManager.FileEntry get() = parent.let { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 5130c0f99dc..c857663a888 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -285,7 +285,7 @@ fun IrAnnotationContainer.getAnnotation(name: FqName): IrConstructorCall? = fun IrAnnotationContainer.hasAnnotation(name: FqName) = annotations.any { - it.symbol.owner.parentAsClass.fqNameWhenAvailable == name + it.symbol.owner.parentAsClass.hasEqualFqName(name) } fun IrAnnotationContainer.hasAnnotation(symbol: IrClassSymbol) =