JVM IR: Avoid unnecessary CHECKCASTs in enum classes

This commit is contained in:
Steven Schäfer
2020-04-22 17:17:19 +02:00
committed by max-kammerer
parent cb3a4727cf
commit b6b8dd1eab
4 changed files with 33 additions and 1 deletions
@@ -539,7 +539,17 @@ class ExpressionCodegen(
ownerType.internalName
} ?: typeMapper.mapClass(callee.parentAsClass).internalName
return if (expression is IrSetField) {
expression.value.accept(this, data).materializeAt(fieldType, callee.type)
val value = expression.value.accept(this, data)
// We only initialize enum entries with a subtype of `fieldType` and can avoid the CHECKCAST.
// This is important for some tools which analyze bytecode for enum classes by looking at the
// initializer of the $VALUES field.
if (callee.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY) {
value.materialize()
} else {
value.materializeAt(fieldType, callee.type)
}
when {
isStatic -> mv.putstatic(ownerName, fieldName, fieldType.descriptor)
else -> mv.putfield(ownerName, fieldName, fieldType.descriptor)
@@ -0,0 +1,12 @@
enum class Foo {
A, B, C { override fun result() = "OK" };
open fun result() = "Fail"
}
// JVM_TEMPLATES:
// There are two CHECKCASTs, one in Foo.valueOf and one in Foo.values
// 2 CHECKCAST
// JVM_IR_TEMPLATES:
// There should be only one CHECKCAST in Foo.valueOf
// 1 CHECKCAST
@@ -1855,6 +1855,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/enum"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("enumCheckcasts.kt")
public void testEnumCheckcasts() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt");
}
@TestMetadata("kt18731.kt")
public void testKt18731() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/enum/kt18731.kt");
@@ -1810,6 +1810,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/enum"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("enumCheckcasts.kt")
public void testEnumCheckcasts() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/enum/enumCheckcasts.kt");
}
@TestMetadata("kt18731.kt")
public void testKt18731() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/enum/kt18731.kt");