diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index e2bbda7713e..ee546a0de4a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -66,8 +66,8 @@ val jvmPhases = namedIrFilePhase( jvmLateinitPhase then moveCompanionObjectFieldsPhase then - constPhase then propertyReferencePhase then + constPhase then propertiesToFieldsPhase then propertiesPhase then renameFieldsPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 467c33ce554..fb713f38d7b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -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) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 11950049d6f..55d3e00b286 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt index bcc94f05153..c22df98c20a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt @@ -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) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt index 30d75c8facd..99997244b22 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/MoveCompanionObjectFieldsLowering.kt @@ -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 diff --git a/compiler/testData/codegen/box/annotations/annotationWithKotlinProperty.kt b/compiler/testData/codegen/box/annotations/annotationWithKotlinProperty.kt index 7074a2a7ceb..90465c615a8 100644 --- a/compiler/testData/codegen/box/annotations/annotationWithKotlinProperty.kt +++ b/compiler/testData/codegen/box/annotations/annotationWithKotlinProperty.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/multifileClasses/constPropertyReferenceFromMultifileClass.kt b/compiler/testData/codegen/box/multifileClasses/constPropertyReferenceFromMultifileClass.kt index 3f6ede057ed..95b5b84301c 100644 --- a/compiler/testData/codegen/box/multifileClasses/constPropertyReferenceFromMultifileClass.kt +++ b/compiler/testData/codegen/box/multifileClasses/constPropertyReferenceFromMultifileClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT // FILE: 1.kt diff --git a/compiler/testData/codegen/box/multifileClasses/optimized/callableRefToConstVal.kt b/compiler/testData/codegen/box/multifileClasses/optimized/callableRefToConstVal.kt index 909d9aca62d..55354181495 100644 --- a/compiler/testData/codegen/box/multifileClasses/optimized/callableRefToConstVal.kt +++ b/compiler/testData/codegen/box/multifileClasses/optimized/callableRefToConstVal.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // IGNORE_LIGHT_ANALYSIS // WITH_RUNTIME diff --git a/compiler/testData/codegen/bytecodeText/constants/kt9532.kt b/compiler/testData/codegen/bytecodeText/constants/kt9532.kt index 3e936561e0b..13e58418348 100644 --- a/compiler/testData/codegen/bytecodeText/constants/kt9532.kt +++ b/compiler/testData/codegen/bytecodeText/constants/kt9532.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR object A { private const val a = "$" private const val b = "1234$a" diff --git a/compiler/testData/codegen/bytecodeText/inlineJavaStaticFields.kt b/compiler/testData/codegen/bytecodeText/inlineJavaStaticFields.kt index f9607b9b87e..f6ae773a90d 100644 --- a/compiler/testData/codegen/bytecodeText/inlineJavaStaticFields.kt +++ b/compiler/testData/codegen/bytecodeText/inlineJavaStaticFields.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // FILE: JClass.java import org.jetbrains.annotations.NotNull; diff --git a/compiler/testData/codegen/bytecodeText/inlineProtectedJavaConstantFromOtherPackage.kt b/compiler/testData/codegen/bytecodeText/inlineProtectedJavaConstantFromOtherPackage.kt index eefbd8f67fb..e81e9b6375a 100644 --- a/compiler/testData/codegen/bytecodeText/inlineProtectedJavaConstantFromOtherPackage.kt +++ b/compiler/testData/codegen/bytecodeText/inlineProtectedJavaConstantFromOtherPackage.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // FILE: first/Foo.java package first; diff --git a/compiler/testData/codegen/bytecodeText/preEvaluateInlineJavaStaticFields.kt b/compiler/testData/codegen/bytecodeText/preEvaluateInlineJavaStaticFields.kt index 261ac74fd8d..a1acf41d438 100644 --- a/compiler/testData/codegen/bytecodeText/preEvaluateInlineJavaStaticFields.kt +++ b/compiler/testData/codegen/bytecodeText/preEvaluateInlineJavaStaticFields.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // FILE: JClass.java import org.jetbrains.annotations.NotNull; diff --git a/compiler/testData/compileJavaAgainstKotlin/property/ConstVal.kt b/compiler/testData/compileJavaAgainstKotlin/property/ConstVal.kt index d2dc8c4fb16..d49c2557401 100644 --- a/compiler/testData/compileJavaAgainstKotlin/property/ConstVal.kt +++ b/compiler/testData/compileJavaAgainstKotlin/property/ConstVal.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR @file:JvmName("ABC") package test; diff --git a/compiler/testData/compileJavaAgainstKotlin/staticFields/AnnotationClass.kt b/compiler/testData/compileJavaAgainstKotlin/staticFields/AnnotationClass.kt index e09adb9fed6..7dce73a33df 100644 --- a/compiler/testData/compileJavaAgainstKotlin/staticFields/AnnotationClass.kt +++ b/compiler/testData/compileJavaAgainstKotlin/staticFields/AnnotationClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR package test annotation class AString(val value: String) diff --git a/compiler/testData/compileJavaAgainstKotlin/staticFields/kt3698.kt b/compiler/testData/compileJavaAgainstKotlin/staticFields/kt3698.kt index c640b45d44d..058b249d9a2 100644 --- a/compiler/testData/compileJavaAgainstKotlin/staticFields/kt3698.kt +++ b/compiler/testData/compileJavaAgainstKotlin/staticFields/kt3698.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR package test class KotlinClass { diff --git a/compiler/testData/compileKotlinAgainstKotlin/callsToMultifileClassFromOtherPackage.kt b/compiler/testData/compileKotlinAgainstKotlin/callsToMultifileClassFromOtherPackage.kt index 9beba374e3c..3c6332d89bb 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/callsToMultifileClassFromOtherPackage.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/callsToMultifileClassFromOtherPackage.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // FILE: A.kt diff --git a/compiler/testData/compileKotlinAgainstKotlin/constPropertyReferenceFromMultifileClass.kt b/compiler/testData/compileKotlinAgainstKotlin/constPropertyReferenceFromMultifileClass.kt index 2af4b05b04e..e2d7069e457 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/constPropertyReferenceFromMultifileClass.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/constPropertyReferenceFromMultifileClass.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // FILE: A.kt diff --git a/compiler/testData/compileKotlinAgainstKotlin/inlinedConstants.kt b/compiler/testData/compileKotlinAgainstKotlin/inlinedConstants.kt index 613da295ebe..51cb24fd65a 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/inlinedConstants.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/inlinedConstants.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // FILE: A.kt diff --git a/compiler/testData/compileKotlinAgainstKotlin/kotlinPropertyAsAnnotationParameter.kt b/compiler/testData/compileKotlinAgainstKotlin/kotlinPropertyAsAnnotationParameter.kt index 429dc5102df..a43165004f0 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/kotlinPropertyAsAnnotationParameter.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/kotlinPropertyAsAnnotationParameter.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // FILE: A.kt diff --git a/compiler/testData/compileKotlinAgainstKotlin/unsignedTypesInAnnotations.kt b/compiler/testData/compileKotlinAgainstKotlin/unsignedTypesInAnnotations.kt index efc7911536c..d82e78d74d8 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/unsignedTypesInAnnotations.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/unsignedTypesInAnnotations.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: NATIVE // WITH_RUNTIME