Generate optimized hashCode for primitive type with jvmTarget 1.8+
#KT-7571 Fixed
This commit is contained in:
@@ -27,10 +27,12 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.HashCode;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmStringTable;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.JvmTarget;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
@@ -512,7 +514,7 @@ public class AsmUtil {
|
||||
});
|
||||
}
|
||||
|
||||
static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
|
||||
static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type, JvmTarget jvmTarget) {
|
||||
if (type.getSort() == Type.ARRAY) {
|
||||
Type elementType = correctElementType(type);
|
||||
if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
|
||||
@@ -525,16 +527,6 @@ public class AsmUtil {
|
||||
else if (type.getSort() == Type.OBJECT) {
|
||||
iv.invokevirtual("java/lang/Object", "hashCode", "()I", false);
|
||||
}
|
||||
else if (type.getSort() == Type.LONG) {
|
||||
genLongHashCode(mv, iv);
|
||||
}
|
||||
else if (type.getSort() == Type.DOUBLE) {
|
||||
iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false);
|
||||
genLongHashCode(mv, iv);
|
||||
}
|
||||
else if (type.getSort() == Type.FLOAT) {
|
||||
iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false);
|
||||
}
|
||||
else if (type.getSort() == Type.BOOLEAN) {
|
||||
Label end = new Label();
|
||||
iv.dup();
|
||||
@@ -543,8 +535,24 @@ public class AsmUtil {
|
||||
iv.iconst(1);
|
||||
iv.mark(end);
|
||||
}
|
||||
else { // byte short char int
|
||||
// do nothing
|
||||
else {
|
||||
if (JvmTarget.JVM_1_6 == jvmTarget) {
|
||||
if (type.getSort() == Type.LONG) {
|
||||
genLongHashCode(mv, iv);
|
||||
}
|
||||
else if (type.getSort() == Type.DOUBLE) {
|
||||
iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false);
|
||||
genLongHashCode(mv, iv);
|
||||
}
|
||||
else if (type.getSort() == Type.FLOAT) {
|
||||
iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false);
|
||||
}
|
||||
else { // byte short char int
|
||||
// do nothing
|
||||
}
|
||||
} else {
|
||||
HashCode.Companion.invokeHashCode(iv, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -573,7 +573,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
iv.ifnull(ifNull);
|
||||
}
|
||||
|
||||
genHashCode(mv, iv, asmType);
|
||||
genHashCode(mv, iv, asmType, state.getTarget());
|
||||
|
||||
if (ifNull != null) {
|
||||
Label end = new Label();
|
||||
|
||||
@@ -16,22 +16,40 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.Callable
|
||||
import org.jetbrains.kotlin.codegen.CallableMethod
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class HashCode : IntrinsicMethod() {
|
||||
override fun toCallable(method: CallableMethod): Callable =
|
||||
object : IntrinsicCallable(
|
||||
Type.INT_TYPE,
|
||||
emptyList(),
|
||||
nullOrObject(method.dispatchReceiverType),
|
||||
nullOrObject(method.extensionReceiverType)
|
||||
) {
|
||||
override fun invokeIntrinsic(v: InstructionAdapter) {
|
||||
v.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I", false)
|
||||
}
|
||||
class HashCode(private val jvmTarget: JvmTarget) : IntrinsicMethod() {
|
||||
override fun toCallable(method: CallableMethod): Callable {
|
||||
val receiverType = method.dispatchReceiverType ?: method.extensionReceiverType ?: error("No receiver for callable: $method")
|
||||
val useObjectHashCode = JvmTarget.JVM_1_6 == jvmTarget || !AsmUtil.isPrimitive(receiverType)
|
||||
return object : IntrinsicCallable(
|
||||
Type.INT_TYPE,
|
||||
emptyList(),
|
||||
if (useObjectHashCode) nullOrObject(method.dispatchReceiverType) else method.dispatchReceiverType,
|
||||
if (useObjectHashCode) nullOrObject(method.extensionReceiverType) else method.extensionReceiverType
|
||||
) {
|
||||
override fun invokeIntrinsic(v: InstructionAdapter) {
|
||||
v.invokeHashCode(if (useObjectHashCode) AsmTypes.OBJECT_TYPE else receiverType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun InstructionAdapter.invokeHashCode(type: Type) {
|
||||
if (AsmUtil.isPrimitive(type)) {
|
||||
val boxedType = AsmUtil.boxType(type)
|
||||
visitMethodInsn(Opcodes.INVOKESTATIC, boxedType.internalName, "hashCode", Type.getMethodDescriptor(Type.INT_TYPE, type), false)
|
||||
}
|
||||
else {
|
||||
visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.config.JvmTarget;
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
@@ -45,7 +47,7 @@ public class IntrinsicMethods {
|
||||
private static final IntrinsicMethod RANGE_TO = new RangeTo();
|
||||
private static final IntrinsicMethod INC = new Increment(1);
|
||||
private static final IntrinsicMethod DEC = new Increment(-1);
|
||||
private static final IntrinsicMethod HASH_CODE = new HashCode();
|
||||
private final IntrinsicMethod HASH_CODE;
|
||||
|
||||
private static final IntrinsicMethod ARRAY_SIZE = new ArraySize();
|
||||
private static final Equals EQUALS = new Equals();
|
||||
@@ -59,7 +61,8 @@ public class IntrinsicMethods {
|
||||
private static final IntrinsicMethod ARRAY_ITERATOR = new ArrayIterator();
|
||||
private final IntrinsicsMap intrinsicsMap = new IntrinsicsMap();
|
||||
|
||||
public IntrinsicMethods() {
|
||||
public IntrinsicMethods(JvmTarget jvmTarget) {
|
||||
HASH_CODE = new HashCode(jvmTarget);
|
||||
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, RECEIVER_PARAMETER_FQ_NAME, "javaClass", -1, JavaClassProperty.INSTANCE);
|
||||
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.kClass, "java", -1, new KClassJavaProperty());
|
||||
intrinsicsMap.registerIntrinsic(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe(), null, "name", -1, new KCallableNameProperty());
|
||||
|
||||
@@ -138,7 +138,7 @@ class GenerationState @JvmOverloads constructor(
|
||||
this.bindingContext, classBuilderMode, fileClassesProvider, IncompatibleClassTrackerImpl(extraJvmDiagnosticsTrace),
|
||||
this.moduleName, isJvm8Target, isJvm8TargetWithDefaults
|
||||
)
|
||||
val intrinsics: IntrinsicMethods = IntrinsicMethods()
|
||||
val intrinsics: IntrinsicMethods = IntrinsicMethods(target)
|
||||
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
|
||||
val inlineCycleReporter: InlineCycleReporter = InlineCycleReporter(diagnostics)
|
||||
val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this)
|
||||
|
||||
Reference in New Issue
Block a user