JVM_IR: set ConstantValue on static final primitive fields

This commit is contained in:
pyos
2019-04-11 12:44:38 +02:00
committed by max-kammerer
parent 14485c0e33
commit b23f2a4dbb
20 changed files with 40 additions and 29 deletions
@@ -66,8 +66,8 @@ val jvmPhases = namedIrFilePhase(
jvmLateinitPhase then
moveCompanionObjectFieldsPhase then
constPhase then
propertyReferencePhase then
constPhase then
propertiesToFieldsPhase then
propertiesPhase then
renameFieldsPhase then
@@ -18,17 +18,17 @@ package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper
import org.jetbrains.kotlin.codegen.inline.SourceMapper
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.source.getPsi
@@ -218,9 +219,13 @@ open class ClassCodegen protected constructor(
val fieldType = typeMapper.mapType(field.descriptor)
val fieldSignature = typeMapper.mapFieldSignature(field.descriptor.type, field.descriptor)
val fieldName = field.descriptor.name.asString()
// The ConstantValue attribute makes the initializer part of the ABI, which is why since 1.4
// it is no longer set unless the property is explicitly `const`.
val implicitConst = !state.languageVersionSettings.supportsFeature(LanguageFeature.NoConstantValueAttributeForNonConstVals) &&
(AsmUtil.isPrimitive(fieldType) || fieldType == AsmTypes.JAVA_STRING_TYPE)
val fv = visitor.newField(
field.OtherOrigin, field.flags, fieldName, fieldType.descriptor,
fieldSignature, null/*TODO support default values*/
fieldSignature, field.constantValue(implicitConst)?.value
)
AnnotationCodegen(this, state, fv::visitAnnotation).genAnnotations(field, fieldType)
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty
import org.jetbrains.kotlin.backend.jvm.intrinsics.Not
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.*
@@ -421,6 +422,14 @@ class ExpressionCodegen(
}
override fun visitFieldAccess(expression: IrFieldAccessExpression, data: BlockInfo): PromisedValue {
expression.symbol.owner.constantValue()?.let {
// Handling const reads before codegen is important for constant folding.
assert(expression is IrSetField) { "read of const val ${expression.symbol.owner.name} not inlined by ConstLowering" }
// This can only be the field's initializer; JVM implementations are required
// to generate those for ConstantValue-marked fields automatically, so this is redundant.
return voidValue.coerce(expression.asmType)
}
val realDescriptor = DescriptorUtils.unwrapFakeOverride(expression.descriptor)
val fieldType = typeMapper.mapType(realDescriptor.original.type)
val ownerType = typeMapper.mapImplementationOwner(expression.descriptor).internalName
@@ -8,11 +8,14 @@ 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.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrField
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.expressions.IrGetField
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -22,19 +25,27 @@ internal val constPhase = makeIrFilePhase(
description = "Substitute calls to const properties with constant values"
)
fun IrField.constantValue(implicitConst: Boolean = false): IrConst<*>? {
// javac always inlines reads of static final fields, so do that for ones imported from Java.
// Kotlin fields are only inlined if explicitly `const` to avoid making the values part of the ABI.
val inline = correspondingPropertySymbol?.owner?.isConst == true ||
(isStatic && isFinal && (origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB || implicitConst))
return if (inline) initializer?.expression as? IrConst<*> else null
}
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)
val function = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression)
val property = function.correspondingPropertySymbol?.owner ?: return super.visitCall(expression)
if (function != property.getter)
return super.visitCall(expression)
return property.backingField?.constantValue() ?: super.visitCall(expression)
}
override fun visitGetField(expression: IrGetField): IrExpression =
expression.symbol.owner.constantValue() ?: super.visitGetField(expression)
}
@@ -101,6 +101,7 @@ private class MoveCompanionObjectFieldsLowering(val context: CommonBackendContex
val newField = createStaticBackingField(oldField, propertyParent, fieldParent)
irProperty.backingField = newField
newField.correspondingPropertySymbol = irProperty.symbol
fieldReplacementMap[oldField.symbol] = newField.symbol
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_REFLECT
// FILE: 1.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
object A {
private const val a = "$"
private const val b = "1234$a"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: JClass.java
import org.jetbrains.annotations.NotNull;
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: first/Foo.java
package first;
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: JClass.java
import org.jetbrains.annotations.NotNull;
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
@file:JvmName("ABC")
package test;
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
package test
annotation class AString(val value: String)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
package test
class KotlinClass {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: A.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: A.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: A.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: A.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: NATIVE
// WITH_RUNTIME