From 8067df3c94fbc719e7562cd307efe5d3d00c7d61 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 25 May 2023 01:38:29 +0200 Subject: [PATCH] [IR] Combine `IrInterpreterNameCheck` with common one This way we achieve faster compilation time. We want to traverse IR tree as little as possible. If we add new checker than the time to evaluate constants basically doubles. #KT-58923 --- .../checker/IrInterpreterCommonChecker.kt | 4 ++ .../checker/IrInterpreterNameChecker.kt | 59 ------------------- .../IrInterpreterKCallableNamePreprocessor.kt | 33 ++++++++++- .../transformer/IrConstTransformer.kt | 30 ++++------ .../intrinsicConst/kCallableName.kt | 2 +- .../kCallableNameWithSideEffect.kt | 2 +- 6 files changed, 50 insertions(+), 80 deletions(-) delete mode 100644 compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt index ed87b48437d..c4d93403202 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterCommonChecker.kt @@ -12,6 +12,8 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.interpreter.accessesTopLevelOrObjectField import org.jetbrains.kotlin.ir.interpreter.fqName import org.jetbrains.kotlin.ir.interpreter.isAccessToNotNullableObject +import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor.Companion.isEnumName +import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor.Companion.isKCallableNameCall import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.parentAsClass @@ -61,6 +63,8 @@ class IrInterpreterCommonChecker : IrInterpreterChecker { val owner = expression.symbol.owner if (!data.mode.canEvaluateFunction(owner)) return false + if (expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName()) return true + if (expression.dispatchReceiver.isAccessToNotNullableObject()) { return expression.isGetterToConstVal() } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt deleted file mode 100644 index d931588662c..00000000000 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrInterpreterNameChecker.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2010-2023 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.ir.interpreter.checker - -import org.jetbrains.kotlin.ir.IrBuiltIns -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrProperty -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.expressions.IrCall -import org.jetbrains.kotlin.ir.expressions.IrCallableReference -import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue -import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation -import org.jetbrains.kotlin.ir.interpreter.property -import org.jetbrains.kotlin.ir.util.isSubclassOf - -class IrInterpreterNameChecker : IrInterpreterChecker { - override fun visitElement(element: IrElement, data: IrInterpreterCheckerData) = false - - override fun visitCall(expression: IrCall, data: IrInterpreterCheckerData): Boolean { - val owner = expression.symbol.owner - if (!data.mode.canEvaluateFunction(owner)) return false - - return expression.isKCallableNameCall(data.irBuiltIns) || expression.isEnumName() - } - - override fun visitStringConcatenation(expression: IrStringConcatenation, data: IrInterpreterCheckerData): Boolean { - val possibleNameCall = expression.arguments.singleOrNull() as? IrCall ?: return false - return possibleNameCall.accept(this, data) - } - - companion object { - fun IrCall.isKCallableNameCall(irBuiltIns: IrBuiltIns): Boolean { - if (this.dispatchReceiver !is IrCallableReference<*>) return false - - val directMember = this.symbol.owner.let { it.property ?: it } - - val irClass = directMember.parent as? IrClass ?: return false - if (!irClass.isSubclassOf(irBuiltIns.kCallableClass.owner)) return false - - val name = when (directMember) { - is IrSimpleFunction -> directMember.name - is IrProperty -> directMember.name - else -> throw AssertionError("Should be IrSimpleFunction or IrProperty, got $directMember") - } - return name.asString() == "name" - } - - private fun IrCall.isEnumName(): Boolean { - val owner = this.symbol.owner - if (owner.extensionReceiverParameter != null || owner.valueParameters.isNotEmpty()) return false - val property = owner.property ?: return false - return this.dispatchReceiver is IrGetEnumValue && property.name.asString() == "name" - } - } -} diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/preprocessor/IrInterpreterKCallableNamePreprocessor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/preprocessor/IrInterpreterKCallableNamePreprocessor.kt index 651a2c45304..876c7977583 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/preprocessor/IrInterpreterKCallableNamePreprocessor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/preprocessor/IrInterpreterKCallableNamePreprocessor.kt @@ -5,12 +5,18 @@ package org.jetbrains.kotlin.ir.interpreter.preprocessor +import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCallableReference +import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl -import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterNameChecker.Companion.isKCallableNameCall +import org.jetbrains.kotlin.ir.interpreter.property +import org.jetbrains.kotlin.ir.util.isSubclassOf import org.jetbrains.kotlin.name.SpecialNames // Note: this class still will not allow us to evaluate things like `A()::a.name + `A()::b.name`. @@ -33,4 +39,29 @@ class IrInterpreterKCallableNamePreprocessor : IrInterpreterPreprocessor { expression.startOffset, expression.endOffset, expression.type, origin = null, statements = listOf(receiver, expression) ) } + + companion object { + fun IrCall.isKCallableNameCall(irBuiltIns: IrBuiltIns): Boolean { + if (this.dispatchReceiver !is IrCallableReference<*>) return false + + val directMember = this.symbol.owner.let { it.property ?: it } + + val irClass = directMember.parent as? IrClass ?: return false + if (!irClass.isSubclassOf(irBuiltIns.kCallableClass.owner)) return false + + val name = when (directMember) { + is IrSimpleFunction -> directMember.name + is IrProperty -> directMember.name + else -> throw AssertionError("Should be IrSimpleFunction or IrProperty, got $directMember") + } + return name.asString() == "name" + } + + fun IrCall.isEnumName(): Boolean { + val owner = this.symbol.owner + if (owner.extensionReceiverParameter != null || owner.valueParameters.isNotEmpty()) return false + val property = owner.property ?: return false + return this.dispatchReceiver is IrGetEnumValue && property.name.asString() == "name" + } + } } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt index ee7aa1e9216..9ca4216c3c4 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt @@ -38,25 +38,19 @@ fun IrFile.transformConst( preprocessor.preprocess(file, IrInterpreterPreprocessorData(mode, interpreter.irBuiltIns)) } - val checkers = setOf( - IrInterpreterNameChecker(), - IrInterpreterCommonChecker(), + val checker = IrInterpreterCommonChecker() + val irConstExpressionTransformer = IrConstExpressionTransformer( + interpreter, preprocessedFile, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions ) - - checkers.fold(preprocessedFile) { file, checker -> - val irConstExpressionTransformer = IrConstExpressionTransformer( - interpreter, file, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions - ) - val irConstDeclarationAnnotationTransformer = IrConstDeclarationAnnotationTransformer( - interpreter, file, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions - ) - val irConstTypeAnnotationTransformer = IrConstTypeAnnotationTransformer( - interpreter, file, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions - ) - file.transform(irConstExpressionTransformer, null) - file.transform(irConstDeclarationAnnotationTransformer, null) - file.transform(irConstTypeAnnotationTransformer, null) - } + val irConstDeclarationAnnotationTransformer = IrConstDeclarationAnnotationTransformer( + interpreter, preprocessedFile, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions + ) + val irConstTypeAnnotationTransformer = IrConstTypeAnnotationTransformer( + interpreter, preprocessedFile, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions + ) + preprocessedFile.transform(irConstExpressionTransformer, null) + preprocessedFile.transform(irConstDeclarationAnnotationTransformer, null) + preprocessedFile.transform(irConstTypeAnnotationTransformer, null) } // Note: We are using `IrElementTransformer` here instead of `IrElementTransformerVoid` to avoid conflicts with `IrTypeVisitorVoid` diff --git a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableName.kt b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableName.kt index 41eb7be4069..eed382697a7 100644 --- a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableName.kt +++ b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableName.kt @@ -15,7 +15,7 @@ const val methodName = A::foo.name const val suspendMethodName = A::bar.name const val className = ::A.")!>name const val topLevelPropName = ::topLevelProp.name -const val nameInComplexExpression = A::OK.name + "!" +const val nameInComplexExpression = A::OK.name + "!" // STOP_EVALUATION_CHECKS fun box(): String { diff --git a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt index 261623cb357..f0abd4d85eb 100644 --- a/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt +++ b/compiler/testData/codegen/box/involvesIrInterpreter/intrinsicConst/kCallableNameWithSideEffect.kt @@ -27,7 +27,7 @@ class A { val insideStringConcat = "${temp::b.name}" val complexExpression1 = A()::a.name + A()::b.name - val complexExpression2 = A::a.name + A::b.name + val complexExpression2 = A::a.name + A::b.name var recursive = ::test.name }