[JVM_IR] Box primitive types in class literals of reified type arguments

Bytecode inliner boxes primitive types in class literals of reified type
arguments. This is by design, and we should backport this behaviour to
IR inliner.

^KT-60144: Fixed
This commit is contained in:
vladislav.grechko
2023-07-20 20:43:52 +02:00
committed by Space Team
parent ade1354a84
commit cfcdc6f0ae
15 changed files with 66 additions and 25 deletions
@@ -326,6 +326,16 @@ private val apiVersionIsAtLeastEvaluationPhase = makeIrModulePhase(
prerequisite = setOf(functionInliningPhase)
)
private val inlinedClassReferencesBoxingPhase = makeIrModulePhase(
{ context ->
if (!context.irInlinerIsEnabled()) return@makeIrModulePhase FileLoweringPass.Empty
InlinedClassReferencesBoxingLowering(context)
},
name = "InlinedClassReferencesBoxingLowering",
description = "Replace inlined primitive types in class references with boxed versions",
prerequisite = setOf(functionInliningPhase, markNecessaryInlinedClassesAsRegenerated)
)
private val constEvaluationPhase = makeIrModulePhase<JvmBackendContext>(
::ConstEvaluationLowering,
name = "ConstEvaluationLowering",
@@ -476,6 +486,7 @@ private fun buildJvmLoweringPhases(
apiVersionIsAtLeastEvaluationPhase then
createSeparateCallForInlinedLambdas then
markNecessaryInlinedClassesAsRegenerated then
inlinedClassReferencesBoxingPhase then
buildLoweringsPhase(phases) then
generateMultifileFacadesPhase then
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.getAttributeOwnerBeforeInline
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrClassReference
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
internal class InlinedClassReferencesBoxingLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementVisitorVoid {
override fun lower(irFile: IrFile) {
irFile.acceptChildrenVoid(this)
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitClassReference(expression: IrClassReference) {
super.visitClassReference(expression)
val wasTypeParameterClassRefBeforeInline =
(expression.getAttributeOwnerBeforeInline() as? IrClassReference)?.classType?.classifierOrNull is IrTypeParameterSymbol
if (wasTypeParameterClassRefBeforeInline && expression.classType.isPrimitiveType()) {
// Making primitive type nullable is effectively boxing
val boxedPrimitive = expression.classType.makeNullable()
require(boxedPrimitive is IrSimpleType) {
"Type is expected to be ${IrSimpleType::class.simpleName}: ${boxedPrimitive.render()}"
}
expression.classType = boxedPrimitive
val classReferenceType = expression.type
require(classReferenceType is IrSimpleType && classReferenceType.isKClass()) {
"Type of the type reference is expected to be KClass: ${classReferenceType.render()}"
}
expression.type = classReferenceType.buildSimpleType {
arguments = listOf(boxedPrimitive)
}
}
}
}
@@ -937,14 +937,14 @@ class JvmSymbols(
throw AssertionError("Array type expected: ${arrayType.render()}")
}
private val javaLangInteger: IrClassSymbol = createJavaPrimitiveClass(FqName("java.lang.Integer"), irBuiltIns.intType)
val javaLangInteger: IrClassSymbol = createJavaPrimitiveClass(FqName("java.lang.Integer"), irBuiltIns.intType)
val compareUnsignedInt: IrSimpleFunctionSymbol = javaLangInteger.functionByName("compareUnsigned")
val divideUnsignedInt: IrSimpleFunctionSymbol = javaLangInteger.functionByName("divideUnsigned")
val remainderUnsignedInt: IrSimpleFunctionSymbol = javaLangInteger.functionByName("remainderUnsigned")
val toUnsignedStringInt: IrSimpleFunctionSymbol = javaLangInteger.functionByName("toUnsignedString")
private val javaLangLong: IrClassSymbol = createJavaPrimitiveClass(FqName("java.lang.Long"), irBuiltIns.longType)
val javaLangLong: IrClassSymbol = createJavaPrimitiveClass(FqName("java.lang.Long"), irBuiltIns.longType)
val compareUnsignedLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("compareUnsigned")
val divideUnsignedLong: IrSimpleFunctionSymbol = javaLangLong.functionByName("divideUnsigned")
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
inline fun <reified T : Any> check(expected: String) {
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
-2
View File
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
-1
View File
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_INLINER: IR
// WITH_STDLIB
import kotlin.test.assertEquals