JVM_IR: Fix enum classes ABI
1. Enum entry fields don't have nullability annotations. 2. Enum class special methods (values, valueOf) are not 'final' (although they probably should be, javac generates corresponding methods without ACC_FINAL flag). 3. Enum class special methods don't have nullability annotations. 4. Don't generate synthetic accessor for enum entry class constructor. KT-37019 KT-37020 KT-37021
This commit is contained in:
+1
-1
@@ -245,7 +245,7 @@ abstract class ClassCodegen protected constructor(
|
|||||||
|
|
||||||
if (field.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS_RESULT_FIELD) {
|
if (field.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS_RESULT_FIELD) {
|
||||||
val skipNullabilityAnnotations =
|
val skipNullabilityAnnotations =
|
||||||
flags and Opcodes.ACC_SYNTHETIC != 0 || flags and Opcodes.ACC_PRIVATE != 0 ||
|
flags and (Opcodes.ACC_SYNTHETIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_ENUM) != 0 ||
|
||||||
field.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_STATIC_LAMBDA_INSTANCE
|
field.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_STATIC_LAMBDA_INSTANCE
|
||||||
object : AnnotationCodegen(this@ClassCodegen, context, skipNullabilityAnnotations) {
|
object : AnnotationCodegen(this@ClassCodegen, context, skipNullabilityAnnotations) {
|
||||||
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
|
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
|
||||||
|
|||||||
+3
-1
@@ -70,7 +70,8 @@ class FunctionCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER &&
|
if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER &&
|
||||||
irFunction.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
|
irFunction.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR &&
|
||||||
|
irFunction.origin != IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER
|
||||||
) {
|
) {
|
||||||
val skipNullabilityAnnotations = flags and Opcodes.ACC_PRIVATE != 0 || flags and Opcodes.ACC_SYNTHETIC != 0
|
val skipNullabilityAnnotations = flags and Opcodes.ACC_PRIVATE != 0 || flags and Opcodes.ACC_SYNTHETIC != 0
|
||||||
object : AnnotationCodegen(classCodegen, context, skipNullabilityAnnotations) {
|
object : AnnotationCodegen(classCodegen, context, skipNullabilityAnnotations) {
|
||||||
@@ -145,6 +146,7 @@ class FunctionCodegen(
|
|||||||
val modalityFlag = when ((this as? IrSimpleFunction)?.modality) {
|
val modalityFlag = when ((this as? IrSimpleFunction)?.modality) {
|
||||||
Modality.FINAL -> when {
|
Modality.FINAL -> when {
|
||||||
origin == JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER -> 0
|
origin == JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER -> 0
|
||||||
|
origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER -> 0
|
||||||
parentAsClass.isInterface && body != null -> 0
|
parentAsClass.isInterface && body != null -> 0
|
||||||
parentAsClass.isAnnotationClass && !isStatic -> Opcodes.ACC_ABSTRACT
|
parentAsClass.isAnnotationClass && !isStatic -> Opcodes.ACC_ABSTRACT
|
||||||
else -> Opcodes.ACC_FINAL
|
else -> Opcodes.ACC_FINAL
|
||||||
|
|||||||
+3
@@ -576,6 +576,9 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
|
|||||||
// There is never a problem with visibility of inline functions, as those don't end up as Java entities
|
// There is never a problem with visibility of inline functions, as those don't end up as Java entities
|
||||||
if (declaration is IrFunction && declaration.isInline) return true
|
if (declaration is IrFunction && declaration.isInline) return true
|
||||||
|
|
||||||
|
// Enum entry constructors are generated as package-private and are accessed only from corresponding enum class
|
||||||
|
if (declaration is IrConstructor && declaration.constructedClass.isEnumEntry) return true
|
||||||
|
|
||||||
// `internal` maps to public and requires no accessor.
|
// `internal` maps to public and requires no accessor.
|
||||||
if (!withSuper && !declaration.visibility.isPrivate && !declaration.visibility.isProtected) return true
|
if (!withSuper && !declaration.visibility.isPrivate && !declaration.visibility.isProtected) return true
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
enum class SimpleEnum {
|
||||||
|
A, B, C
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class WithConstructor(val x: String) {
|
||||||
|
A("1"), B("2"), C("3")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class WithEntryClass {
|
||||||
|
A {
|
||||||
|
override fun foo() {}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
abstract fun foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
annotation class Ann
|
||||||
|
|
||||||
|
enum class WithAnnotations {
|
||||||
|
@Ann A, @Ann B
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
@java.lang.annotation.Retention
|
||||||
|
@kotlin.Metadata
|
||||||
|
public annotation class Ann
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final enum class SimpleEnum {
|
||||||
|
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
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(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 {
|
||||||
|
private synthetic final static field $VALUES: WithAnnotations[]
|
||||||
|
public final enum static @Ann field A: WithAnnotations
|
||||||
|
public final enum static @Ann field B: WithAnnotations
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(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 {
|
||||||
|
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 field x: java.lang.String
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(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 {
|
||||||
|
inner class WithEntryClass$A
|
||||||
|
method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public method foo(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public abstract enum class WithEntryClass {
|
||||||
|
private synthetic final static field $VALUES: WithEntryClass[]
|
||||||
|
public final enum static field A: WithEntryClass
|
||||||
|
inner class WithEntryClass$A
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(p0: java.lang.String, p1: int): void
|
||||||
|
public synthetic method <init>(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[]
|
||||||
|
}
|
||||||
@@ -13,7 +13,6 @@ fun main() {
|
|||||||
value<Z>()
|
value<Z>()
|
||||||
}
|
}
|
||||||
|
|
||||||
// JVM_TEMPLATES
|
|
||||||
//2 reifiedOperationMarker
|
//2 reifiedOperationMarker
|
||||||
//1 INVOKESTATIC kotlin/jvm/internal/Intrinsics\.reifiedOperationMarker \(ILjava/lang/String;\)V\s*ICONST_0\s*ANEWARRAY java/lang/Enum
|
//1 INVOKESTATIC kotlin/jvm/internal/Intrinsics\.reifiedOperationMarker \(ILjava/lang/String;\)V\s*ICONST_0\s*ANEWARRAY java/lang/Enum
|
||||||
//1 INVOKESTATIC Z\.values \(\)\[LZ;
|
//1 INVOKESTATIC Z\.values \(\)\[LZ;
|
||||||
@@ -22,14 +21,3 @@ fun main() {
|
|||||||
//1 INVOKESTATIC Z\.valueOf \(Ljava/lang/String;\)LZ;
|
//1 INVOKESTATIC Z\.valueOf \(Ljava/lang/String;\)LZ;
|
||||||
//1 public static valueOf
|
//1 public static valueOf
|
||||||
//2 INVOKESTATIC java/lang/Enum.valueOf \(Ljava/lang/Class;Ljava/lang/String;\)Ljava/lang/Enum;
|
//2 INVOKESTATIC java/lang/Enum.valueOf \(Ljava/lang/Class;Ljava/lang/String;\)Ljava/lang/Enum;
|
||||||
|
|
||||||
// JVM_IR_TEMPLATES
|
|
||||||
//2 reifiedOperationMarker
|
|
||||||
//1 INVOKESTATIC kotlin/jvm/internal/Intrinsics\.reifiedOperationMarker \(ILjava/lang/String;\)V\s*ICONST_0\s*ANEWARRAY java/lang/Enum
|
|
||||||
//1 INVOKESTATIC Z\.values \(\)\[LZ;
|
|
||||||
//4 valueOf
|
|
||||||
//1 INVOKESTATIC kotlin/jvm/internal/Intrinsics\.reifiedOperationMarker \(ILjava/lang/String;\)V\s*ACONST_NULL\s*ALOAD 2\s*INVOKESTATIC java/lang/Enum\.valueOf \(Ljava/lang/Class;Ljava/lang/String;\)Ljava/lang/Enum;
|
|
||||||
//1 INVOKESTATIC Z\.valueOf \(Ljava/lang/String;\)LZ;
|
|
||||||
//1 public final static valueOf
|
|
||||||
// ^ valueOf is generated as 'public final static' in JVM_IR
|
|
||||||
//2 INVOKESTATIC java/lang/Enum.valueOf \(Ljava/lang/Class;Ljava/lang/String;\)Ljava/lang/Enum;
|
|
||||||
+5
@@ -54,6 +54,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeListing/emptyMultifileFacade.kt");
|
runTest("compiler/testData/codegen/bytecodeListing/emptyMultifileFacade.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enum.kt")
|
||||||
|
public void testEnum() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeListing/enum.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("extension.kt")
|
@TestMetadata("extension.kt")
|
||||||
public void testExtension() throws Exception {
|
public void testExtension() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeListing/extension.kt");
|
runTest("compiler/testData/codegen/bytecodeListing/extension.kt");
|
||||||
|
|||||||
+5
@@ -54,6 +54,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
|||||||
runTest("compiler/testData/codegen/bytecodeListing/emptyMultifileFacade.kt");
|
runTest("compiler/testData/codegen/bytecodeListing/emptyMultifileFacade.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enum.kt")
|
||||||
|
public void testEnum() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/bytecodeListing/enum.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("extension.kt")
|
@TestMetadata("extension.kt")
|
||||||
public void testExtension() throws Exception {
|
public void testExtension() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeListing/extension.kt");
|
runTest("compiler/testData/codegen/bytecodeListing/extension.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user