From 0a11385006e874dff25609a0c0cb48767515dd31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Peltier?= Date: Thu, 5 Apr 2018 09:03:45 +0200 Subject: [PATCH] KT-12330 Improve bytecode for data class equals/hashCode methods - Do not longer call hashCode on java/lang/Object but do this on statically checked type. - Do not longer call Intrinsics.areEqual but use directly equals method on statically checked type. Fix of https://youtrack.jetbrains.com/issue/KT-12330 --- .../org/jetbrains/kotlin/codegen/AsmUtil.java | 5 +++-- .../codegen/ImplementationBodyCodegen.java | 17 ++++++++++++++--- .../codegen/bytecodeText/dataClasses/kt12330.kt | 4 ++++ .../codegen/BytecodeTextTestGenerated.java | 15 +++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeText/dataClasses/kt12330.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 6cd8eeccbd7..f16e251bf65 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt; import org.jetbrains.kotlin.resolve.inline.InlineUtil; +import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType; import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo; @@ -506,7 +507,7 @@ public class AsmUtil { }); } - static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type, JvmTarget jvmTarget) { + static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type, JvmTarget jvmTarget, boolean isInterface) { if (type.getSort() == Type.ARRAY) { Type elementType = correctElementType(type); if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) { @@ -517,7 +518,7 @@ public class AsmUtil { } } else if (type.getSort() == Type.OBJECT) { - iv.invokevirtual("java/lang/Object", "hashCode", "()I", false); + iv.invokevirtual((isInterface ? AsmTypes.OBJECT_TYPE : type).getInternalName(), "hashCode", "()I", false); } else if (type.getSort() == Type.BOOLEAN) { Label end = new Label(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index a7abbb1a071..09aebc0bc82 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; +import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature; @@ -573,8 +574,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.ifne(ne); } else { - StackValue value = genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.onStack(asmType), StackValue.onStack(asmType)); - value.put(Type.BOOLEAN_TYPE, iv); + if (isPrimitive(asmType)) { + StackValue value = StackValue.cmp(KtTokens.EQEQ, asmType, StackValue.onStack(asmType), StackValue.onStack(asmType)); + value.put(Type.BOOLEAN_TYPE, iv); + } else { + Type owner = + DescriptorUtils.isInterface(propertyDescriptor.getType().getConstructor().getDeclarationDescriptor()) + ? AsmTypes.OBJECT_TYPE + : asmType; + iv.invokevirtual(owner.getInternalName(), "equals", + Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE), false); + } iv.ifeq(ne); } } @@ -615,7 +625,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.ifnull(ifNull); } - genHashCode(mv, iv, asmType, state.getTarget()); + genHashCode(mv, iv, asmType, state.getTarget(), + DescriptorUtils.isInterface(propertyDescriptor.getType().getConstructor().getDeclarationDescriptor())); if (ifNull != null) { Label end = new Label(); diff --git a/compiler/testData/codegen/bytecodeText/dataClasses/kt12330.kt b/compiler/testData/codegen/bytecodeText/dataClasses/kt12330.kt new file mode 100644 index 00000000000..42a675886e7 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/dataClasses/kt12330.kt @@ -0,0 +1,4 @@ +data class D(val x: List) + +// 1 INVOKEVIRTUAL java/lang/Object.hashCode +// 1 INVOKEVIRTUAL java/lang/Object.equals \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 01027ccbcd3..a9318e2a83f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1225,6 +1225,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeText/dataClasses") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DataClasses extends AbstractBytecodeTextTest { + public void testAllFilesPresentInDataClasses() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/dataClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("kt12330.kt") + public void testKt12330() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/dataClasses/kt12330.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)