From 7cc06489dd7fe3a644a76a1f5cce505c3238a6b2 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Wed, 6 Jan 2021 21:56:29 -0800 Subject: [PATCH] IR: move enum value array initialization out of #KT-44192 Fixed --- .../backend/jvm/lower/EnumClassLowering.kt | 37 +++++-- .../ir/declarations/IrDeclarationOrigin.kt | 1 + compiler/testData/codegen/box/enum/bigEnum.kt | 2 - .../deprecatedEnumEntryFields_ir.txt | 13 +++ .../codegen/bytecodeListing/enum_ir.txt | 71 ++++++++++++++ ...ineClassTypeParametersInConstructor_ir.txt | 97 +++++++++++++++++++ .../bytecodeListing/annoOnNotClass_ir.txt | 45 +++++++++ 7 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeListing/deprecated/deprecatedEnumEntryFields_ir.txt create mode 100644 compiler/testData/codegen/bytecodeListing/enum_ir.txt create mode 100644 compiler/testData/codegen/bytecodeListing/inlineClasses/inlineClassTypeParametersInConstructor_ir.txt create mode 100644 plugins/noarg/noarg-cli/testData/bytecodeListing/annoOnNotClass_ir.txt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt index 677627b26be..1fc66f8c086 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.addField +import org.jetbrains.kotlin.ir.builders.declarations.addFunction import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor import org.jetbrains.kotlin.ir.declarations.* @@ -46,6 +47,8 @@ internal val enumClassPhase = makeIrFilePhase( description = "Handle enum classes" ) +private const val VALUES_HELPER_FUNCTION_NAME = "\$values" + private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass { override fun lower(irClass: IrClass) { if (!irClass.isEnumClass) return @@ -69,13 +72,16 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP irClass.declarations.removeAll { it is IrEnumEntry } irClass.declarations += declarationToEnumEntry.keys - // Construct the synthetic $VALUES field, which contains an array of all enum entries - val valuesField = buildValuesField() + // Construct the synthetic $values() function, which creates an array of all enum entries + val valuesHelperFunction = buildValuesHelperFunction() + + // Construct the synthetic $VALUES field, which contains an array of all enum entries by calling $values() + val valuesField = buildValuesField(valuesHelperFunction) // Add synthetic parameters to enum constructors and implement the values and valueOf functions irClass.transformChildrenVoid(EnumClassDeclarationsTransformer(valuesField)) - // Add synthetic arguments to enum constructor calls and remap enum constructor paramters + // Add synthetic arguments to enum constructor calls and remap enum constructor parameters irClass.transformChildrenVoid(EnumClassCallTransformer()) } @@ -85,7 +91,22 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP annotations += enumEntry.annotations } - private fun buildValuesField(): IrField = irClass.addField { + private fun buildValuesHelperFunction(): IrFunction = irClass.addFunction { + name = Name.identifier(VALUES_HELPER_FUNCTION_NAME) + returnType = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType) + visibility = DescriptorVisibilities.PRIVATE + origin = IrDeclarationOrigin.SYNTHETIC_HELPER_FOR_ENUM_VALUES + }.apply { + body = context.createJvmIrBuilder(symbol).run { + irExprBody(irArray(returnType) { + for (irField in declarationToEnumEntry.keys.filterIsInstance()) { + +irGetField(null, irField) + } + }) + } + } + + private fun buildValuesField(valuesHelperFunction: IrFunction): IrField = irClass.addField { name = Name.identifier(ImplementationBodyCodegen.ENUM_VALUES_FIELD_NAME) type = context.irBuiltIns.arrayClass.typeWith(irClass.defaultType) visibility = DescriptorVisibilities.PRIVATE @@ -94,11 +115,9 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP isStatic = true }.apply { initializer = context.createJvmIrBuilder(symbol).run { - irExprBody(irArray(type) { - for (irField in declarationToEnumEntry.keys.filterIsInstance()) { - +irGetField(null, irField) - } - }) + irExprBody( + irCall(valuesHelperFunction.symbol) + ) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index eb52fd4f9da..91fa8eb6dbd 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -60,6 +60,7 @@ interface IrDeclarationOrigin { object BRIDGE_SPECIAL : IrDeclarationOriginImpl("BRIDGE_SPECIAL") object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY") + object SYNTHETIC_HELPER_FOR_ENUM_VALUES : IrDeclarationOriginImpl("SYNTHETIC_HELPER_FOR_ENUM_VALUES", isSynthetic = true) object FIELD_FOR_ENUM_VALUES : IrDeclarationOriginImpl("FIELD_FOR_ENUM_VALUES", isSynthetic = true) object FIELD_FOR_OBJECT_INSTANCE : IrDeclarationOriginImpl("FIELD_FOR_OBJECT_INSTANCE") diff --git a/compiler/testData/codegen/box/enum/bigEnum.kt b/compiler/testData/codegen/box/enum/bigEnum.kt index 7fa3be2a551..96202b7a180 100644 --- a/compiler/testData/codegen/box/enum/bigEnum.kt +++ b/compiler/testData/codegen/box/enum/bigEnum.kt @@ -1,7 +1,5 @@ // TARGET_BACKEND: JVM // IGNORE_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_FIR: JVM_IR enum class BigEnum { C0001, C0002, C0003, C0004, C0005, C0006, C0007, C0008, C0009, C0010, diff --git a/compiler/testData/codegen/bytecodeListing/deprecated/deprecatedEnumEntryFields_ir.txt b/compiler/testData/codegen/bytecodeListing/deprecated/deprecatedEnumEntryFields_ir.txt new file mode 100644 index 00000000000..0e5e09e6835 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/deprecated/deprecatedEnumEntryFields_ir.txt @@ -0,0 +1,13 @@ +@kotlin.Metadata +public final enum class Test { + // source: 'deprecatedEnumEntryFields.kt' + private synthetic final static field $VALUES: Test[] + public deprecated final enum static @kotlin.Deprecated field ENTRY1: Test + public final enum static field ENTRY2: Test + public deprecated final enum static @kotlin.Deprecated field ENTRY3: Test + private synthetic final static method $values(): Test[] + static method (): void + private method (p0: java.lang.String, p1: int): void + public static method valueOf(p0: java.lang.String): Test + public static method values(): Test[] +} diff --git a/compiler/testData/codegen/bytecodeListing/enum_ir.txt b/compiler/testData/codegen/bytecodeListing/enum_ir.txt new file mode 100644 index 00000000000..0b56f38dbac --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/enum_ir.txt @@ -0,0 +1,71 @@ +@java.lang.annotation.Retention +@kotlin.Metadata +public annotation class Ann { + // source: 'enum.kt' +} + +@kotlin.Metadata +public final enum class SimpleEnum { + // source: 'enum.kt' + private synthetic final static field $VALUES: SimpleEnum[] + public final enum static field A: SimpleEnum + public final enum static field B: SimpleEnum + public final enum static field C: SimpleEnum + private synthetic final static method $values(): SimpleEnum[] + static method (): void + private method (p0: java.lang.String, p1: int): void + public static method valueOf(p0: java.lang.String): SimpleEnum + public static method values(): SimpleEnum[] +} + +@kotlin.Metadata +public final enum class WithAnnotations { + // source: 'enum.kt' + private synthetic final static field $VALUES: WithAnnotations[] + public final enum static @Ann field A: WithAnnotations + public final enum static @Ann field B: WithAnnotations + private synthetic final static method $values(): WithAnnotations[] + static method (): void + private method (p0: java.lang.String, p1: int): void + public static method valueOf(p0: java.lang.String): WithAnnotations + public static method values(): WithAnnotations[] +} + +@kotlin.Metadata +public final enum class WithConstructor { + // source: 'enum.kt' + private synthetic final static field $VALUES: WithConstructor[] + public final enum static field A: WithConstructor + public final enum static field B: WithConstructor + public final enum static field C: WithConstructor + private final @org.jetbrains.annotations.NotNull field x: java.lang.String + private synthetic final static method $values(): WithConstructor[] + static method (): void + private method (p0: java.lang.String, p1: int, p2: java.lang.String): void + public final @org.jetbrains.annotations.NotNull method getX(): java.lang.String + public static method valueOf(p0: java.lang.String): WithConstructor + public static method values(): WithConstructor[] +} + +@kotlin.Metadata +final class WithEntryClass$A { + // source: 'enum.kt' + final inner class WithEntryClass$A + method (p0: java.lang.String, p1: int): void + public method foo(): void +} + +@kotlin.Metadata +public abstract enum class WithEntryClass { + // source: 'enum.kt' + private synthetic final static field $VALUES: WithEntryClass[] + public final enum static field A: WithEntryClass + final inner class WithEntryClass$A + private synthetic final static method $values(): WithEntryClass[] + static method (): void + private method (p0: java.lang.String, p1: int): void + public synthetic method (p0: java.lang.String, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void + public abstract method foo(): void + public static method valueOf(p0: java.lang.String): WithEntryClass + public static method values(): WithEntryClass[] +} diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineClassTypeParametersInConstructor_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineClassTypeParametersInConstructor_ir.txt new file mode 100644 index 00000000000..0b81a29abc8 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineClassTypeParametersInConstructor_ir.txt @@ -0,0 +1,97 @@ +@kotlin.Metadata +public interface PrivateMarker { + // source: 'inlineClassTypeParametersInConstructor.kt' +} + +@kotlin.Metadata +public interface ProtectedMarker { + // source: 'inlineClassTypeParametersInConstructor.kt' +} + +@kotlin.Metadata +public interface PublicMarker { + // source: 'inlineClassTypeParametersInConstructor.kt' +} + +@kotlin.Metadata +public class TestBasic { + // source: 'inlineClassTypeParametersInConstructor.kt' + private final field z: int + private method (p0: int): void + private method (p0: int, p1: PrivateMarker): void + private method (p0: int, p1: ProtectedMarker): void + public synthetic method (p0: int, p1: ProtectedMarker, p2: kotlin.jvm.internal.DefaultConstructorMarker): void + private method (p0: int, p1: PublicMarker): void + public synthetic method (p0: int, p1: PublicMarker, p2: kotlin.jvm.internal.DefaultConstructorMarker): void + public synthetic method (p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void + public final method getZ-a_XrcN0(): int +} + +@kotlin.Metadata +public final enum class TestEnum { + // source: 'inlineClassTypeParametersInConstructor.kt' + private synthetic final static field $VALUES: TestEnum[] + public final enum static field ANSWER: TestEnum + private final field z: int + private synthetic final static method $values(): TestEnum[] + static method (): void + private method (p0: java.lang.String, p1: int, p2: int): void + public final method getZ-a_XrcN0(): int + public static method valueOf(p0: java.lang.String): TestEnum + public static method values(): TestEnum[] +} + +@kotlin.Metadata +public final class TestInner$Inner { + // source: 'inlineClassTypeParametersInConstructor.kt' + synthetic final field this$0: TestInner + private final field z: int + private method (p0: TestInner, p1: int): void + public synthetic method (p0: TestInner, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void + public final method getZ-a_XrcN0(): int + public final inner class TestInner$Inner +} + +@kotlin.Metadata +public final class TestInner { + // source: 'inlineClassTypeParametersInConstructor.kt' + public method (): void + public final inner class TestInner$Inner +} + +@kotlin.Metadata +public final class TestSealed$Case { + // source: 'inlineClassTypeParametersInConstructor.kt' + private method (p0: int): void + public synthetic method (p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void + public final inner class TestSealed$Case +} + +@kotlin.Metadata +public abstract class TestSealed { + // source: 'inlineClassTypeParametersInConstructor.kt' + private final field z: int + private method (p0: int): void + public synthetic method (p0: int, p1: kotlin.jvm.internal.DefaultConstructorMarker): void + public final method getZ-a_XrcN0(): int + public final inner class TestSealed$Case +} + +@kotlin.jvm.JvmInline +@kotlin.Metadata +public final class Z { + // source: 'inlineClassTypeParametersInConstructor.kt' + private final field x: int + private synthetic method (p0: int): void + public synthetic final static method box-impl(p0: int): Z + public static method constructor-impl(p0: int): int + public method equals(p0: java.lang.Object): boolean + public static method equals-impl(p0: int, p1: java.lang.Object): boolean + public final static method equals-impl0(p0: int, p1: int): boolean + public final method getX(): int + public method hashCode(): int + public static method hashCode-impl(p0: int): int + public method toString(): java.lang.String + public static method toString-impl(p0: int): java.lang.String + public synthetic final method unbox-impl(): int +} diff --git a/plugins/noarg/noarg-cli/testData/bytecodeListing/annoOnNotClass_ir.txt b/plugins/noarg/noarg-cli/testData/bytecodeListing/annoOnNotClass_ir.txt new file mode 100644 index 00000000000..630566ca6c5 --- /dev/null +++ b/plugins/noarg/noarg-cli/testData/bytecodeListing/annoOnNotClass_ir.txt @@ -0,0 +1,45 @@ +@NoArg +@kotlin.Metadata +public final enum class Colors { + // source: 'annoOnNotClass.kt' + private synthetic final static field $VALUES: Colors[] + public final enum static field RED: Colors + public final enum static field WHITE: Colors + private synthetic final static method $values(): Colors[] + static method (): void + private method (p0: java.lang.String, p1: int): void + public static method valueOf(p0: java.lang.String): Colors + public static method values(): Colors[] +} + +@NoArg +@kotlin.Metadata +public interface Intf { + // source: 'annoOnNotClass.kt' +} + +@kotlin.Metadata +public final class MyClass { + // source: 'annoOnNotClass.kt' + private @NoArg @org.jetbrains.annotations.NotNull field abc: java.lang.String + public method (p0: int): void + public final @NoArg @org.jetbrains.annotations.NotNull method getAbc(): java.lang.String + public final @NoArg method setAbc(@org.jetbrains.annotations.NotNull p0: java.lang.String): void + public final @NoArg method someFun(): void +} + +@NoArg +@java.lang.annotation.Retention +@kotlin.Metadata +public annotation class NoArg { + // source: 'annoOnNotClass.kt' +} + +@NoArg +@kotlin.Metadata +public final class Obj { + // source: 'annoOnNotClass.kt' + public final static @org.jetbrains.annotations.NotNull field INSTANCE: Obj + static method (): void + private method (): void +}