JVM_IR: set ConstantValue on static final primitive fields
This commit is contained in:
@@ -66,8 +66,8 @@ val jvmPhases = namedIrFilePhase(
|
|||||||
jvmLateinitPhase then
|
jvmLateinitPhase then
|
||||||
|
|
||||||
moveCompanionObjectFieldsPhase then
|
moveCompanionObjectFieldsPhase then
|
||||||
constPhase then
|
|
||||||
propertyReferencePhase then
|
propertyReferencePhase then
|
||||||
|
constPhase then
|
||||||
propertiesToFieldsPhase then
|
propertiesToFieldsPhase then
|
||||||
propertiesPhase then
|
propertiesPhase then
|
||||||
renameFieldsPhase 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.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
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.*
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||||
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper
|
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper
|
||||||
import org.jetbrains.kotlin.codegen.inline.SourceMapper
|
import org.jetbrains.kotlin.codegen.inline.SourceMapper
|
||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
|
||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
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.psi.KtElement
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration
|
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.JvmDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
@@ -218,9 +219,13 @@ open class ClassCodegen protected constructor(
|
|||||||
val fieldType = typeMapper.mapType(field.descriptor)
|
val fieldType = typeMapper.mapType(field.descriptor)
|
||||||
val fieldSignature = typeMapper.mapFieldSignature(field.descriptor.type, field.descriptor)
|
val fieldSignature = typeMapper.mapFieldSignature(field.descriptor.type, field.descriptor)
|
||||||
val fieldName = field.descriptor.name.asString()
|
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(
|
val fv = visitor.newField(
|
||||||
field.OtherOrigin, field.flags, fieldName, fieldType.descriptor,
|
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)
|
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.JavaClassProperty
|
||||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.Not
|
import org.jetbrains.kotlin.backend.jvm.intrinsics.Not
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
|
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.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil.*
|
import org.jetbrains.kotlin.codegen.AsmUtil.*
|
||||||
@@ -421,6 +422,14 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFieldAccess(expression: IrFieldAccessExpression, data: BlockInfo): PromisedValue {
|
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 realDescriptor = DescriptorUtils.unwrapFakeOverride(expression.descriptor)
|
||||||
val fieldType = typeMapper.mapType(realDescriptor.original.type)
|
val fieldType = typeMapper.mapType(realDescriptor.original.type)
|
||||||
val ownerType = typeMapper.mapImplementationOwner(expression.descriptor).internalName
|
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.CommonBackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
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.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
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.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
@@ -22,19 +25,27 @@ internal val constPhase = makeIrFilePhase(
|
|||||||
description = "Substitute calls to const properties with constant values"
|
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 {
|
class ConstLowering(val context: CommonBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
irFile.transformChildrenVoid(this)
|
irFile.transformChildrenVoid(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
val irSimpleFunction = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression)
|
val function = (expression.symbol.owner as? IrSimpleFunction) ?: return super.visitCall(expression)
|
||||||
val irProperty = irSimpleFunction.correspondingProperty ?: return super.visitCall(expression)
|
val property = function.correspondingPropertySymbol?.owner ?: return super.visitCall(expression)
|
||||||
|
if (function != property.getter)
|
||||||
if (irProperty.isConst) {
|
return super.visitCall(expression)
|
||||||
(irProperty.backingField!!.initializer!!.expression as IrConst<*>).let { return it }
|
return property.backingField?.constantValue() ?: super.visitCall(expression)
|
||||||
}
|
|
||||||
|
|
||||||
return 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)
|
val newField = createStaticBackingField(oldField, propertyParent, fieldParent)
|
||||||
|
|
||||||
irProperty.backingField = newField
|
irProperty.backingField = newField
|
||||||
|
newField.correspondingPropertySymbol = irProperty.symbol
|
||||||
|
|
||||||
fieldReplacementMap[oldField.symbol] = newField.symbol
|
fieldReplacementMap[oldField.symbol] = newField.symbol
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// IGNORE_LIGHT_ANALYSIS
|
// IGNORE_LIGHT_ANALYSIS
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
object A {
|
object A {
|
||||||
private const val a = "$"
|
private const val a = "$"
|
||||||
private const val b = "1234$a"
|
private const val b = "1234$a"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FILE: JClass.java
|
// FILE: JClass.java
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FILE: first/Foo.java
|
// FILE: first/Foo.java
|
||||||
|
|
||||||
package first;
|
package first;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FILE: JClass.java
|
// FILE: JClass.java
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
@file:JvmName("ABC")
|
@file:JvmName("ABC")
|
||||||
package test;
|
package test;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
package test
|
package test
|
||||||
|
|
||||||
annotation class AString(val value: String)
|
annotation class AString(val value: String)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
package test
|
package test
|
||||||
|
|
||||||
class KotlinClass {
|
class KotlinClass {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// FILE: A.kt
|
// FILE: A.kt
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// FILE: A.kt
|
// FILE: A.kt
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// FILE: A.kt
|
// FILE: A.kt
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// FILE: A.kt
|
// FILE: A.kt
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// IGNORE_BACKEND: NATIVE
|
// IGNORE_BACKEND: NATIVE
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user