JVM IR: Optimize equality on class literals
This commit is contained in:
committed by
Alexander Udalov
parent
3a1d83e7c5
commit
a90c4d5dd5
+10
-9
@@ -1390,21 +1390,22 @@ class ExpressionCodegen(
|
||||
return MaterialValue(this@ExpressionCodegen, JAVA_STRING_TYPE, context.irBuiltIns.stringType)
|
||||
}
|
||||
|
||||
override fun visitGetClass(expression: IrGetClass, data: BlockInfo) =
|
||||
generateClassLiteralReference(expression, true, data)
|
||||
override fun visitGetClass(expression: IrGetClass, data: BlockInfo): PromisedValue =
|
||||
generateClassLiteralReference(expression, wrapIntoKClass = true, wrapPrimitives = false, data = data)
|
||||
|
||||
override fun visitClassReference(expression: IrClassReference, data: BlockInfo) =
|
||||
generateClassLiteralReference(expression, true, data)
|
||||
override fun visitClassReference(expression: IrClassReference, data: BlockInfo): PromisedValue =
|
||||
generateClassLiteralReference(expression, wrapIntoKClass = true, wrapPrimitives = false, data = data)
|
||||
|
||||
fun generateClassLiteralReference(
|
||||
classReference: IrExpression,
|
||||
wrapIntoKClass: Boolean,
|
||||
wrapPrimitives: Boolean,
|
||||
data: BlockInfo
|
||||
): PromisedValue {
|
||||
): MaterialValue {
|
||||
when (classReference) {
|
||||
is IrGetClass -> {
|
||||
// TODO transform one sort of access into the other?
|
||||
JavaClassProperty.invokeWith(classReference.argument.accept(this, data))
|
||||
JavaClassProperty.invokeWith(classReference.argument.accept(this, data), wrapPrimitives)
|
||||
}
|
||||
is IrClassReference -> {
|
||||
val classType = classReference.classType
|
||||
@@ -1416,7 +1417,7 @@ class ExpressionCodegen(
|
||||
}
|
||||
}
|
||||
|
||||
generateClassInstance(mv, classType, typeMapper)
|
||||
generateClassInstance(mv, classType, typeMapper, wrapPrimitives)
|
||||
}
|
||||
else -> {
|
||||
throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}")
|
||||
@@ -1521,9 +1522,9 @@ class ExpressionCodegen(
|
||||
get() = this.classifierOrNull?.safeAs<IrTypeParameterSymbol>()?.owner?.isReified == true
|
||||
|
||||
companion object {
|
||||
internal fun generateClassInstance(v: InstructionAdapter, classType: IrType, typeMapper: IrTypeMapper) {
|
||||
internal fun generateClassInstance(v: InstructionAdapter, classType: IrType, typeMapper: IrTypeMapper, wrapPrimitives: Boolean) {
|
||||
val asmType = typeMapper.mapType(classType)
|
||||
if (classType.getClass()?.isSingleFieldValueClass == true || !isPrimitive(asmType)) {
|
||||
if (wrapPrimitives || classType.getClass()?.isSingleFieldValueClass == true || !isPrimitive(asmType)) {
|
||||
v.aconst(typeMapper.boxType(classType))
|
||||
} else {
|
||||
v.getstatic(boxType(asmType).internalName, "TYPE", "Ljava/lang/Class;")
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ class IrInlineIntrinsicsSupport(
|
||||
get() = context.state
|
||||
|
||||
override fun putClassInstance(v: InstructionAdapter, type: IrType) {
|
||||
ExpressionCodegen.generateClassInstance(v, type, typeMapper)
|
||||
ExpressionCodegen.generateClassInstance(v, type, typeMapper, wrapPrimitives = false)
|
||||
}
|
||||
|
||||
override fun generateTypeParameterContainer(v: InstructionAdapter, typeParameter: TypeParameterMarker) {
|
||||
|
||||
+23
-16
@@ -18,15 +18,10 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.ir.declarations.isSingleFieldValueClass
|
||||
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.util.isEnumClass
|
||||
import org.jetbrains.kotlin.ir.util.isEnumEntry
|
||||
import org.jetbrains.kotlin.ir.util.isIntegerConst
|
||||
import org.jetbrains.kotlin.ir.util.isNullConst
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
@@ -110,15 +105,21 @@ class Equals(val operator: IElementType) : IntrinsicMethod() {
|
||||
}
|
||||
|
||||
// We can use reference equality for enums, otherwise we fall back to boxed equality.
|
||||
val aIsEnum = a.type.classOrNull?.owner?.run { isEnumClass || isEnumEntry } == true
|
||||
val bIsEnum = b.type.classOrNull?.owner?.run { isEnumClass || isEnumEntry } == true
|
||||
return if (aIsEnum || bIsEnum) {
|
||||
referenceEquals(a, b, leftType, codegen, data)
|
||||
} else {
|
||||
a.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType)
|
||||
b.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType)
|
||||
genAreEqualCall(codegen.mv)
|
||||
MaterialValue(codegen, Type.BOOLEAN_TYPE, codegen.context.irBuiltIns.booleanType)
|
||||
return when {
|
||||
a.isEnumValue || b.isEnumValue ->
|
||||
referenceEquals(a, b, leftType, codegen, data)
|
||||
|
||||
a.isClassValue && b.isClassValue -> {
|
||||
val leftValue = codegen.generateClassLiteralReference(a, wrapIntoKClass = false, wrapPrimitives = true, data = data)
|
||||
val rightValue = codegen.generateClassLiteralReference(b, wrapIntoKClass = false, wrapPrimitives = true, data = data)
|
||||
BooleanComparison(operator, leftValue, rightValue)
|
||||
}
|
||||
else -> {
|
||||
a.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType)
|
||||
b.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType)
|
||||
genAreEqualCall(codegen.mv)
|
||||
MaterialValue(codegen, Type.BOOLEAN_TYPE, codegen.context.irBuiltIns.booleanType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +140,12 @@ class Equals(val operator: IElementType) : IntrinsicMethod() {
|
||||
BooleanComparison(operator, leftValue, rightValue)
|
||||
}
|
||||
}
|
||||
|
||||
private val IrExpression.isEnumValue: Boolean
|
||||
get() = type.classOrNull?.owner?.run { isEnumClass || isEnumEntry } == true
|
||||
|
||||
private val IrExpression.isClassValue: Boolean
|
||||
get() = this is IrGetClass || this is IrClassReference
|
||||
}
|
||||
|
||||
|
||||
|
||||
+8
-4
@@ -30,7 +30,7 @@ object JavaClassProperty : IntrinsicMethod() {
|
||||
value.mv.invokevirtual("java/lang/Object", "getClass", "()Ljava/lang/Class;", false)
|
||||
}
|
||||
|
||||
fun invokeWith(value: PromisedValue) =
|
||||
fun invokeWith(value: PromisedValue, wrapPrimitives: Boolean) =
|
||||
when {
|
||||
value.type == Type.VOID_TYPE ->
|
||||
invokeGetClass(value.materializedAt(AsmTypes.UNIT_TYPE, value.codegen.context.irBuiltIns.unitType))
|
||||
@@ -38,14 +38,18 @@ object JavaClassProperty : IntrinsicMethod() {
|
||||
invokeGetClass(value.materializedAtBoxed(value.irType))
|
||||
isPrimitive(value.type) -> {
|
||||
value.discard()
|
||||
value.mv.getstatic(boxType(value.type).internalName, "TYPE", "Ljava/lang/Class;")
|
||||
if (wrapPrimitives) {
|
||||
value.mv.aconst(boxType(value.type))
|
||||
} else {
|
||||
value.mv.getstatic(boxType(value.type).internalName, "TYPE", "Ljava/lang/Class;")
|
||||
}
|
||||
}
|
||||
else ->
|
||||
invokeGetClass(value.materialized())
|
||||
}
|
||||
|
||||
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
|
||||
invokeWith(expression.extensionReceiver!!.accept(codegen, data))
|
||||
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue {
|
||||
invokeWith(expression.extensionReceiver!!.accept(codegen, data), wrapPrimitives = false)
|
||||
return with(codegen) { expression.onStack }
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -28,6 +28,6 @@ object KClassJavaProperty : IntrinsicMethod() {
|
||||
val extensionReceiver = expression.extensionReceiver
|
||||
if (extensionReceiver !is IrClassReference && extensionReceiver !is IrGetClass)
|
||||
return null
|
||||
return codegen.generateClassLiteralReference(extensionReceiver, false, data)
|
||||
return codegen.generateClassLiteralReference(extensionReceiver, wrapIntoKClass = false, wrapPrimitives = false, data = data)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user