[K/N] Separate fun-ref to IrConstantObject conversion from FunctionReferenceLowering (KT-71046)
* to help make FunctionReferenceLowering unified as much as possibly across the backends
Merge-request: KT-MR-17899
Merged-by: Alexey Glushko <aleksei.glushko@jetbrains.com>
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/NativeLoweringPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/NativeLoweringPhases.kt
index d0fd30a..2393887 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/NativeLoweringPhases.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/NativeLoweringPhases.kt
@@ -355,6 +355,13 @@
prerequisite = setOf(localFunctionsPhase) // TODO: make weak dependency on `testProcessorPhase`
)
+private val staticFunctionReferenceOptimizationPhase = createFileLoweringPhase(
+ lowering = ::StaticFunctionReferenceOptimization,
+ name = "StaticFunctionReferenceOptimization",
+ description = "Static function reference optimization",
+ prerequisite = setOf(functionReferencePhase, delegationPhase)
+)
+
private val enumWhenPhase = createFileLoweringPhase(
::NativeEnumWhenLowering,
name = "EnumWhen",
@@ -664,6 +671,7 @@
testProcessorPhase.takeIf { context.config.configuration.getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) != TestRunnerKind.NONE },
functionReferencePhase,
delegationPhase,
+ staticFunctionReferenceOptimizationPhase,
singleAbstractMethodPhase,
enumWhenPhase,
finallyBlocksPhase,
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt
index d46a302..f82d669 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionReferenceLowering.kt
@@ -455,16 +455,13 @@
val constructor = buildConstructor()
val arguments = functionReference.getArgumentsWithIr()
val typeArguments = typeParametersFromEnclosingScope.map { it.defaultType }
- val expression = if (arguments.isEmpty()) {
- irBuilder.irConstantObject(clazz, emptyMap(), typeArguments)
- } else {
- irBuilder.irCallConstructor(constructor.symbol, typeArguments).apply {
- arguments.forEachIndexed { index, argument ->
- putValueArgument(index, argument.second)
- }
+ val constrCall = irBuilder.irCallConstructor(constructor.symbol, typeArguments).apply {
+ arguments.forEachIndexed { index, argument ->
+ putValueArgument(index, argument.second)
}
}
- return BuiltFunctionReference(clazz, expression)
+
+ return BuiltFunctionReference(clazz, constrCall)
}
private fun IrBuilderWithScope.getDescription() : IrConstantValue {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/StaticFunctionReferenceOptimization.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/StaticFunctionReferenceOptimization.kt
new file mode 100644
index 0000000..957ad51
--- /dev/null
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/StaticFunctionReferenceOptimization.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the LICENSE file.
+ */
+
+package org.jetbrains.kotlin.backend.konan.lower
+
+import org.jetbrains.kotlin.backend.common.FileLoweringPass
+import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
+import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
+import org.jetbrains.kotlin.backend.konan.Context
+import org.jetbrains.kotlin.backend.konan.lower.FunctionReferenceLowering.Companion.isLoweredFunctionReference
+import org.jetbrains.kotlin.ir.builders.irConstantObject
+import org.jetbrains.kotlin.ir.declarations.IrFile
+import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.ir.util.constructedClass
+import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
+
+/**
+ * Function references are lowered into instantion of on object of some "callable" type.
+ * e.g. `call(::foo)` will be lowered to something like `call(foo$FUNCTION_REFERENCE$0())`.
+ *
+ * In some cases the object instantiated doesn't capture any context and in fact can be replaced with a constant object.
+ * That's what this optimization pass does.
+ */
+internal class StaticFunctionReferenceOptimization(val context: Context) : FileLoweringPass {
+ override fun lower(irFile: IrFile) {
+ irFile.transform(object : IrElementTransformerVoidWithContext() {
+ override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
+ expression.transformChildrenVoid(this)
+
+ val constructor = expression.symbol.owner
+ val constructedClass = constructor.constructedClass
+
+ if (isLoweredFunctionReference(constructedClass) && expression.valueArgumentsCount == 0) {
+ val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol,
+ expression.startOffset, expression.endOffset)
+
+ return irBuilder.irConstantObject(constructedClass, emptyMap(), expression.getClassTypeArguments().map { it!! })
+ } else {
+ return expression
+ }
+ }
+ }, data = null)
+ }
+}
\ No newline at end of file