JVM: Generate equals-impl0 method for inline classes

This commit is contained in:
Steven Schäfer
2019-08-22 12:09:28 +02:00
committed by Alexander Udalov
parent 2c7da67600
commit f53b28e8a3
5 changed files with 45 additions and 32 deletions
@@ -861,6 +861,33 @@ public class AsmUtil {
}); });
} }
@NotNull
public static BranchedValue genTotalOrderEqualsForExpressionOnStack(
@NotNull StackValue left,
@NotNull StackValue right,
@NotNull Type asmType
) {
return new BranchedValue(left, right, asmType, Opcodes.IFEQ) {
@Override
public void condJump(@NotNull Label jumpLabel, @NotNull InstructionAdapter iv, boolean jumpIfFalse) {
if (asmType.getSort() == Type.FLOAT) {
left.put(asmType, kotlinType, iv);
right.put(asmType, kotlinType, iv);
iv.invokestatic("java/lang/Float", "compare", "(FF)I", false);
iv.visitJumpInsn(patchOpcode(jumpIfFalse ? Opcodes.IFNE : Opcodes.IFEQ, iv), jumpLabel);
} else if (asmType.getSort() == Type.DOUBLE) {
left.put(asmType, kotlinType, iv);
right.put(asmType, kotlinType, iv);
iv.invokestatic("java/lang/Double", "compare", "(DD)I", false);
iv.visitJumpInsn(patchOpcode(jumpIfFalse ? Opcodes.IFNE : Opcodes.IFEQ, iv), jumpLabel);
} else {
StackValue value = genEqualsForExpressionsOnStack(KtTokens.EQEQ, left, right);
BranchedValue.Companion.condJump(value, jumpLabel, jumpIfFalse, iv);
}
}
};
}
@NotNull @NotNull
public static StackValue genEqualsBoxedOnStack(@NotNull IElementType opToken) { public static StackValue genEqualsBoxedOnStack(@NotNull IElementType opToken) {
return StackValue.operation(Type.BOOLEAN_TYPE, v -> genAreEqualCall(v, opToken)); return StackValue.operation(Type.BOOLEAN_TYPE, v -> genAreEqualCall(v, opToken));
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.AsmUtil.genTotalOrderEqualsForExpressionOnStack
import org.jetbrains.kotlin.codegen.context.ClassContext import org.jetbrains.kotlin.codegen.context.ClassContext
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Type
class ErasedInlineClassBodyCodegen( class ErasedInlineClassBodyCodegen(
aClass: KtClass, aClass: KtClass,
@@ -109,11 +111,17 @@ class ErasedInlineClassBodyCodegen(
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
val iv = codegen.v val firstIndex = codegen.frameMap.getIndex(specializedEqualsDescriptor.valueParameters[0])
iv.aconst(null) val secondIndex = codegen.frameMap.getIndex(specializedEqualsDescriptor.valueParameters[1])
iv.athrow() val asmType = signature.valueParameters[0].asmType
val left = StackValue.local(firstIndex, asmType)
val right = StackValue.local(secondIndex, asmType)
genTotalOrderEqualsForExpressionOnStack(left, right, asmType).put(Type.BOOLEAN_TYPE, codegen.v)
codegen.v.areturn(Type.BOOLEAN_TYPE)
} }
override fun skipNotNullAssertionsForParameters(): Boolean = true
} }
) )
} }
} }
@@ -251,25 +251,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
return Unit.INSTANCE; return Unit.INSTANCE;
}); });
if (asmType.getSort() == Type.FLOAT) { genTotalOrderEqualsForExpressionOnStack(thisPropertyValue, otherPropertyValue, asmType).condJump(ne, iv, true);
thisPropertyValue.put(asmType, kotlinType, iv);
otherPropertyValue.put(asmType, kotlinType, iv);
iv.invokestatic("java/lang/Float", "compare", "(FF)I", false);
iv.ifne(ne);
}
else if (asmType.getSort() == Type.DOUBLE) {
thisPropertyValue.put(asmType, kotlinType, iv);
otherPropertyValue.put(asmType, kotlinType, iv);
iv.invokestatic("java/lang/Double", "compare", "(DD)I", false);
iv.ifne(ne);
}
else {
StackValue value = genEqualsForExpressionsOnStack(
KtTokens.EQEQ, thisPropertyValue, otherPropertyValue
);
value.put(Type.BOOLEAN_TYPE, iv);
iv.ifeq(ne);
}
} }
iv.mark(eq); iv.mark(eq);
@@ -15,11 +15,7 @@ fun box(): String {
Simple::class.java.getDeclaredMethod(name, String::class.java, String::class.java) Simple::class.java.getDeclaredMethod(name, String::class.java, String::class.java)
?: return "$name not found" ?: return "$name not found"
val result = try { if (specializedEquals.invoke(null, "a", "b") as Boolean)
specializedEquals.invoke(null, "a", "b") return "Fail"
} catch (e: InvocationTargetException) { return "OK"
return if (e.targetException is NullPointerException) "OK" else "${e.targetException}"
}
return if (result == false) "OK" else "Fail"
} }
@@ -2,7 +2,7 @@
inline class AsNonNullPrimitive(val i: Int) inline class AsNonNullPrimitive(val i: Int)
inline class AsNonNullReference(val s: String) inline class AsNonNullReference(val s: String)
// ^ JVM: 5 assertions (constructor, box method, erased constructor, 2 assertions in equals--impl) // ^ JVM: 3 assertions (constructor, box method, erased constructor)
// JVM IR: 1 assertion (erased constructor) // JVM IR: 1 assertion (erased constructor)
fun nonNullPrimitive(a: AsNonNullPrimitive) {} fun nonNullPrimitive(a: AsNonNullPrimitive) {}
@@ -14,7 +14,7 @@ fun asNullablePrimitive(c: AsNonNullPrimitive?) {}
fun asNullableReference(c: AsNonNullReference?) {} fun asNullableReference(c: AsNonNullReference?) {}
// JVM_TEMPLATES // JVM_TEMPLATES
// 8 checkParameterIsNotNull // 6 checkParameterIsNotNull
// 0 checkNotNullParameter // 0 checkNotNullParameter
// JVM_IR_TEMPLATES // JVM_IR_TEMPLATES