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
This commit is contained in:
committed by
Alexander Udalov
parent
e6baf0296d
commit
0a11385006
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
|||||||
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
|
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
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.JvmClassName;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
|
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) {
|
if (type.getSort() == Type.ARRAY) {
|
||||||
Type elementType = correctElementType(type);
|
Type elementType = correctElementType(type);
|
||||||
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
|
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
|
||||||
@@ -517,7 +518,7 @@ public class AsmUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type.getSort() == Type.OBJECT) {
|
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) {
|
else if (type.getSort() == Type.BOOLEAN) {
|
||||||
Label end = new Label();
|
Label end = new Label();
|
||||||
|
|||||||
@@ -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.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
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.JvmDeclarationOrigin;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature;
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature;
|
||||||
@@ -573,8 +574,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
iv.ifne(ne);
|
iv.ifne(ne);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
StackValue value = genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.onStack(asmType), StackValue.onStack(asmType));
|
if (isPrimitive(asmType)) {
|
||||||
value.put(Type.BOOLEAN_TYPE, iv);
|
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);
|
iv.ifeq(ne);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,7 +625,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
iv.ifnull(ifNull);
|
iv.ifnull(ifNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
genHashCode(mv, iv, asmType, state.getTarget());
|
genHashCode(mv, iv, asmType, state.getTarget(),
|
||||||
|
DescriptorUtils.isInterface(propertyDescriptor.getType().getConstructor().getDeclarationDescriptor()));
|
||||||
|
|
||||||
if (ifNull != null) {
|
if (ifNull != null) {
|
||||||
Label end = new Label();
|
Label end = new Label();
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
data class D(val x: List<String>)
|
||||||
|
|
||||||
|
// 1 INVOKEVIRTUAL java/lang/Object.hashCode
|
||||||
|
// 1 INVOKEVIRTUAL java/lang/Object.equals
|
||||||
@@ -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")
|
@TestMetadata("compiler/testData/codegen/bytecodeText/deadCodeElimination")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user