JVM IR: replace unnecessary property accessor calls with field access

Split the ConstAndJvmFieldPropertiesLowering into two: ConstLowering
which replaces const vals with their values, and
PropertiesToFieldsLowering which removes unnecessary property accessors
(such as for JvmField or private properties with default accessors) and
replaces calls to those accessors with field access
This commit is contained in:
Alexander Udalov
2019-02-05 15:19:20 +01:00
committed by Alexander Udalov
parent 1c143310ac
commit ce7d8a6874
7 changed files with 77 additions and 26 deletions
@@ -16,7 +16,7 @@
package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.jvm.lower.*
@@ -46,7 +46,8 @@ internal val jvmPhases = namedIrFilePhase(
jvmLateinitPhase then
moveCompanionObjectFieldsPhase then
constAndJvmFieldPropertiesPhase then
constPhase then
propertiesToFieldsPhase then
propertiesPhase then
annotationPhase then
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.CommonBackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal val constPhase = makeIrFilePhase(
::ConstLowering,
name = "Const",
description = "Substitute calls to const properties with constant values"
)
class ConstLowering(val context: CommonBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(this)
}
override fun visitCall(expression: IrCall): IrExpression {
val irSimpleFunction = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression)
val irProperty = irSimpleFunction.correspondingProperty ?: return super.visitCall(expression)
if (irProperty.isConst) {
(irProperty.backingField!!.initializer!!.expression as IrConst<*>).let { return it }
}
return super.visitCall(expression)
}
}
@@ -10,9 +10,14 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.hasAnnotation
@@ -20,45 +25,54 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME
internal val constAndJvmFieldPropertiesPhase = makeIrFilePhase(
::ConstAndJvmFieldPropertiesLowering,
name = "ConstAndJvmFieldProperties",
description = "Substitute calls to const and Jvm>Field properties with const/field access"
internal val propertiesToFieldsPhase = makeIrFilePhase(
::PropertiesToFieldsLowering,
name = "PropertiesToFields",
description = "Replace calls to default property accessors with field access and remove those accessors"
)
private class ConstAndJvmFieldPropertiesLowering(val context: CommonBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
class PropertiesToFieldsLowering(val context: CommonBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(this)
}
override fun visitProperty(declaration: IrProperty): IrStatement {
if (declaration.isConst || declaration.backingField?.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) == true) {
/*Safe or need copy?*/
if (declaration.isConst || shouldSubstituteAccessorWithField(declaration, declaration.getter)) {
declaration.getter = null
}
if (declaration.isConst || shouldSubstituteAccessorWithField(declaration, declaration.setter)) {
declaration.setter = null
}
return super.visitProperty(declaration)
}
override fun visitCall(expression: IrCall): IrExpression {
val irSimpleFunction = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression)
val irProperty = irSimpleFunction.correspondingProperty ?: return super.visitCall(expression)
val simpleFunction = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression)
val property = simpleFunction.correspondingProperty ?: return super.visitCall(expression)
if (irProperty.isConst) {
(irProperty.backingField!!.initializer!!.expression as IrConst<*>).let { return it }
}
if (irProperty.backingField?.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) == true) {
return if (expression is IrGetterCallImpl) {
substituteGetter(irProperty, expression)
} else {
assert(expression is IrSetterCallImpl)
substituteSetter(irProperty, expression)
if (shouldSubstituteAccessorWithField(property, simpleFunction)) {
when (expression) {
is IrGetterCallImpl -> return substituteGetter(property, expression)
is IrSetterCallImpl -> return substituteSetter(property, expression)
}
}
return super.visitCall(expression)
}
private fun shouldSubstituteAccessorWithField(property: IrProperty, accessor: IrSimpleFunction?): Boolean {
if (accessor == null) return false
// In contrast to the old backend, we do generate getters for lateinit properties, which fixes KT-28331
if (property.isLateinit) return false
if ((property.parent as? IrClass)?.kind == ClassKind.ANNOTATION_CLASS) return false
if (property.backingField?.hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) == true) return true
return accessor.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR && Visibilities.isPrivate(accessor.visibility)
}
private fun substituteSetter(irProperty: IrProperty, expression: IrCall): IrExpression {
val backingField = irProperty.backingField!!
val receiver = expression.dispatchReceiver?.transform(this, null)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// Checks that methods 'access$getMy$p', 'access$getMy$cp' and 'getMy' are not generated and
// that backed field 'my' is directly used through a 'getstatic'
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
package a
class A {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
package a
class A {