JVM_IR: set ConstantValue on static final primitive fields
This commit is contained in:
@@ -66,8 +66,8 @@ val jvmPhases = namedIrFilePhase(
|
||||
jvmLateinitPhase then
|
||||
|
||||
moveCompanionObjectFieldsPhase then
|
||||
constPhase then
|
||||
propertyReferencePhase then
|
||||
constPhase then
|
||||
propertiesToFieldsPhase then
|
||||
propertiesPhase then
|
||||
renameFieldsPhase then
|
||||
|
||||
+10
-5
@@ -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)
|
||||
|
||||
+9
@@ -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
|
||||
|
||||
+19
-8
@@ -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)
|
||||
}
|
||||
|
||||
+1
@@ -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
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
// FILE: 1.kt
|
||||
|
||||
-1
@@ -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
@@ -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
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: A.kt
|
||||
|
||||
|
||||
-1
@@ -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
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user