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:
committed by
Alexander Udalov
parent
1c143310ac
commit
ce7d8a6874
@@ -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)
|
||||
}
|
||||
}
|
||||
+34
-20
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user