[JVM IR] Drop ConstLowering

It basically can be replaced with IR interpreter. The only half-hack
was required in `PropertyReferenceLowering`. Const interpreter is
running before it, so we can't optimize some calls on const
properties that appear after this lowering. Solution is to inline
constants manually during property reference lowering.
This commit is contained in:
Ivan Kylchik
2023-06-15 17:15:07 +02:00
committed by Space Team
parent 1bf3bde4f8
commit d1a54a522d
7 changed files with 84 additions and 51 deletions
@@ -369,7 +369,6 @@ private val jvmFilePhases = listOf(
singletonOrConstantDelegationPhase,
propertyReferencePhase,
arrayConstructorPhase,
constPhase1,
// TODO: merge the next three phases together, as visitors behave incorrectly between them
// (backing fields moved out of companion objects are reachable by two paths):
@@ -422,7 +421,6 @@ private val jvmFilePhases = listOf(
tailCallOptimizationPhase,
addContinuationPhase,
constPhase2, // handle const properties in default arguments of "original" suspend funs
innerClassesPhase,
innerClassesMemberBodyPhase,
@@ -1,45 +0,0 @@
/*
* Copyright 2010-2019 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.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.InlineConstTransformer
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.constantValue
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.incremental.components.InlineConstTracker
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.interpreter.transformer.reportOnIr
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal val constPhase1 = makeIrFilePhase(
::ConstLowering,
name = "Const1",
description = "Substitute calls to const properties with constant values"
)
internal val constPhase2 = makeIrFilePhase(
::ConstLowering,
name = "Const2",
description = "Substitute calls to const properties with constant values"
)
class ConstLowering(val context: JvmBackendContext) : FileLoweringPass {
val inlineConstTracker =
context.state.configuration[CommonConfigurationKeys.INLINE_CONST_TRACKER]
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid(JvmInlineConstTransformer(irFile, inlineConstTracker))
}
private class JvmInlineConstTransformer(val irFile: IrFile, val inlineConstTracker: InlineConstTracker?) : InlineConstTransformer() {
override val IrField.constantInitializer get() = constantValue()
override fun reportInlineConst(field: IrField, value: IrConst<*>) {
inlineConstTracker?.reportOnIr(irFile, field, value)
}
}
@@ -65,6 +65,17 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
private val IrMemberAccessExpression<*>.field: IrFieldSymbol?
get() = (this as? IrPropertyReference)?.field
private val IrMemberAccessExpression<*>.constInitializer: IrExpression?
get() {
if (this !is IrPropertyReference) return null
val constPropertyField = if (field == null) {
symbol.owner.takeIf { it.isConst }?.backingField
} else {
field!!.owner.takeIf { it.isFinal && it.isStatic }
}
return constPropertyField?.initializer?.expression?.shallowCopyOrNull()
}
private val arrayItemGetter =
context.ir.symbols.array.owner.functions.single { it.name.asString() == "get" }
@@ -441,6 +452,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
expression.getter?.owner?.let { getter ->
referenceClass.addOverride(get!!) { arguments ->
expression.constInitializer?.let { return@addOverride it }
irGet(getter.returnType, null, getter.symbol).apply {
setCallArguments(this, arguments)
}
@@ -469,6 +481,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : IrEle
}
referenceClass.addOverride(get!!) { arguments ->
expression.constInitializer?.let { return@addOverride it }
irGetField(fieldReceiver(arguments), field)
}
@@ -0,0 +1,69 @@
/*
* 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.preprocessor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.types.classOrFail
class IrInterpreterConstGetterPreprocessor : IrInterpreterPreprocessor {
override fun visitFunction(declaration: IrFunction, data: IrInterpreterPreprocessorData): IrStatement {
// It is useless to visit default accessor, we probably want to leave code there as it is
if (declaration.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) return declaration
return super.visitFunction(declaration, data)
}
override fun visitCall(expression: IrCall, data: IrInterpreterPreprocessorData): IrElement {
val function = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression, data)
val field = function.correspondingPropertySymbol?.owner?.backingField ?: return super.visitCall(expression, data)
return expression.lowerConstRead(field, data) ?: super.visitCall(expression, data)
}
override fun visitGetField(expression: IrGetField, data: IrInterpreterPreprocessorData): IrExpression {
return expression.lowerConstRead(expression.symbol.owner, data) ?: super.visitGetField(expression, data)
}
private fun IrExpression.lowerConstRead(field: IrField, data: IrInterpreterPreprocessorData): IrExpression? {
val receiver = when (this) {
is IrCall -> dispatchReceiver
is IrGetField -> receiver
else -> return null
}
if (receiver == null || !field.hasConstantValue()) return null
transformChildren(this@IrInterpreterConstGetterPreprocessor, data)
val getObject = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, receiver.type, receiver.type.classOrFail)
when (this) {
is IrCall -> this.dispatchReceiver = getObject
is IrGetField -> this.receiver = getObject
}
return if (receiver.shouldDropConstReceiver()) {
this
} else {
IrCompositeImpl(startOffset, endOffset, this.type, null, listOf(receiver, this))
}
}
private fun IrExpression.shouldDropConstReceiver(): Boolean {
return this is IrGetValue || this is IrGetObjectValue
}
fun IrField.hasConstantValue(): Boolean {
val implicitConst = isFinal && isStatic && origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && initializer != null
return implicitConst || correspondingPropertySymbol?.owner?.isConst == true
}
}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.ir.interpreter.preprocessor
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -18,7 +17,6 @@ import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.interpreter.property
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.classFqName
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.isKFunction
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
import org.jetbrains.kotlin.ir.interpreter.checker.*
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterConstGetterPreprocessor
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor
import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterPreprocessorData
import org.jetbrains.kotlin.ir.interpreter.property
@@ -72,7 +73,7 @@ fun IrFile.preprocessForConstTransformer(
interpreter: IrInterpreter,
mode: EvaluationMode,
): IrFile {
val preprocessors = setOf(IrInterpreterKCallableNamePreprocessor())
val preprocessors = setOf(IrInterpreterKCallableNamePreprocessor(), IrInterpreterConstGetterPreprocessor())
val preprocessedFile = preprocessors.fold(this) { file, preprocessor ->
preprocessor.preprocess(file, IrInterpreterPreprocessorData(mode, interpreter.irBuiltIns))
}
@@ -1,6 +1,5 @@
// IGNORE_BACKEND: NATIVE
// WITH_STDLIB
// WITH_STDLIB
// WITH_REFLECT
// MODULE: lib