[JS IR] Optimize equals call for inline class instances.
Remove implicit boxing of inline class instances in equals call.
This commit is contained in:
committed by
Space
parent
b26a81435f
commit
2ae10f4378
+49
-4
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : CallsTransformer {
|
||||
private val intrinsics = context.intrinsics
|
||||
private val irBuiltIns = context.irBuiltIns
|
||||
private val icUtils = context.inlineClassesUtils
|
||||
|
||||
private val symbolToTransformer: SymbolToTransformer = mutableMapOf()
|
||||
|
||||
@@ -77,12 +78,10 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
|
||||
val lhs = call.getValueArgument(0)!!
|
||||
val rhs = call.getValueArgument(1)!!
|
||||
|
||||
|
||||
val lhsJsType = lhs.type.getPrimitiveType()
|
||||
val rhsJsType = rhs.type.getPrimitiveType()
|
||||
|
||||
val equalsMethod = lhs.type.findEqualsMethod()
|
||||
val isLhsPrimitive = lhsJsType != PrimitiveType.OTHER
|
||||
|
||||
return when {
|
||||
lhs.type is IrDynamicType ->
|
||||
@@ -93,12 +92,16 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
|
||||
irCall(call, intrinsics.jsEqeq)
|
||||
|
||||
// For non-float primitives of the same type use JS `==`
|
||||
isLhsPrimitive && lhsJsType == rhsJsType && lhsJsType != PrimitiveType.FLOATING_POINT_NUMBER ->
|
||||
lhsJsType == rhsJsType && lhsJsType.canBeUsedWithJsEq() ->
|
||||
chooseEqualityOperatorForPrimitiveTypes(call)
|
||||
|
||||
!isLhsPrimitive && !lhs.type.isNullable() && equalsMethod != null ->
|
||||
!lhsJsType.isBuiltin() && !lhs.type.isNullable() && equalsMethod != null ->
|
||||
irCall(call, equalsMethod.symbol, argumentsAsReceivers = true)
|
||||
|
||||
// For inline class instances we can try to unbox them for the equality comparison
|
||||
lhs.isBoxIntrinsic() && rhs.isBoxIntrinsic() ->
|
||||
optimizeInlineClassEquality(call, lhs, rhs)
|
||||
|
||||
else ->
|
||||
irCall(call, intrinsics.jsEquals)
|
||||
}
|
||||
@@ -176,4 +179,46 @@ class EqualityAndComparisonCallsTransformer(context: JsIrBackendContext) : Calls
|
||||
private fun IrFunction.isMethodOfPotentiallyPrimitiveJSType() =
|
||||
isMethodOfPrimitiveJSType() || isFakeOverriddenFromAny()
|
||||
|
||||
private fun PrimitiveType.isBuiltin() =
|
||||
this != PrimitiveType.OTHER
|
||||
|
||||
private fun PrimitiveType.canBeUsedWithJsEq() =
|
||||
isBuiltin() && this != PrimitiveType.FLOATING_POINT_NUMBER
|
||||
|
||||
private fun IrType.isDefaultEqualsMethod() =
|
||||
findEqualsMethod()?.origin === IrDeclarationOrigin.GENERATED_INLINE_CLASS_MEMBER
|
||||
|
||||
private fun IrExpression.isBoxIntrinsic() =
|
||||
this is IrCall && symbol == icUtils.boxIntrinsic
|
||||
|
||||
private fun IrExpression.unboxParamWithInlinedClass(): Pair<IrExpression, IrClass?> {
|
||||
val unboxed = (this as IrFunctionAccessExpression).getValueArgument(0)
|
||||
?: error("Boxed expression is expected")
|
||||
return Pair(unboxed, icUtils.getInlinedClass(unboxed.type))
|
||||
}
|
||||
|
||||
private fun optimizeInlineClassEquality(call: IrFunctionAccessExpression, lhs: IrExpression, rhs: IrExpression): IrExpression {
|
||||
val (lhsUnboxed, lhsClassType) = lhs.unboxParamWithInlinedClass()
|
||||
val (rhsUnboxed, rhsClassType) = rhs.unboxParamWithInlinedClass()
|
||||
if (lhsClassType !== null && lhsClassType === rhsClassType && lhsUnboxed.type.isDefaultEqualsMethod()) {
|
||||
call.putValueArgument(0, lhsUnboxed)
|
||||
call.putValueArgument(1, rhsUnboxed)
|
||||
|
||||
if (lhsUnboxed.type.getLowestUnderlyingType().getPrimitiveType().canBeUsedWithJsEq()) {
|
||||
return chooseEqualityOperatorForPrimitiveTypes(call)
|
||||
}
|
||||
}
|
||||
|
||||
return irCall(call, intrinsics.jsEquals)
|
||||
}
|
||||
|
||||
private fun IrType.getLowestUnderlyingType(): IrType {
|
||||
if (isDefaultEqualsMethod()) {
|
||||
val underlyingType = icUtils.getInlinedClass(this)?.inlineClassRepresentation?.underlyingType
|
||||
if (underlyingType !== null) {
|
||||
return underlyingType.getLowestUnderlyingType()
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user