From cfcdc6f0aea0fb4c734fdaf25ebbce0e749aae20 Mon Sep 17 00:00:00 2001 From: "vladislav.grechko" Date: Thu, 20 Jul 2023 20:43:52 +0200 Subject: [PATCH] [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 --- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 11 ++++ .../InlinedClassReferencesBoxingLowering.kt | 53 +++++++++++++++++++ .../kotlin/backend/jvm/JvmSymbols.kt | 4 +- .../box/classLiteral/java/javaReified.kt | 2 - .../reifiedTypeJavaClass.kt | 2 - .../testData/codegen/box/reified/DIExample.kt | 2 - .../box/reified/anonymousObjectNoPropagate.kt | 2 - .../codegen/box/reified/defaultJavaClass.kt | 2 - .../testData/codegen/box/reified/javaClass.kt | 1 - .../codegen/box/reified/nestedReified.kt | 2 - .../nonInlineableLambdaInReifiedFunction.kt | 2 - .../reified/recursiveNonInlineableLambda.kt | 2 - .../box/reified/reifiedInlineFunOfObject.kt | 2 - .../reifiedInlineFunOfObjectWithinReified.kt | 2 - .../reifiedInlineIntoNonInlineableLambda.kt | 2 - 15 files changed, 66 insertions(+), 25 deletions(-) create mode 100644 compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InlinedClassReferencesBoxingLowering.kt diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 89a2805b90f..6609d2ae023 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -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( ::ConstEvaluationLowering, name = "ConstEvaluationLowering", @@ -476,6 +486,7 @@ private fun buildJvmLoweringPhases( apiVersionIsAtLeastEvaluationPhase then createSeparateCallForInlinedLambdas then markNecessaryInlinedClassesAsRegenerated then + inlinedClassReferencesBoxingPhase then buildLoweringsPhase(phases) then generateMultifileFacadesPhase then diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InlinedClassReferencesBoxingLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InlinedClassReferencesBoxingLowering.kt new file mode 100644 index 00000000000..9dc5891ad54 --- /dev/null +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/InlinedClassReferencesBoxingLowering.kt @@ -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) + } + } + } + +} \ No newline at end of file diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt index 5184da76b94..56a38617248 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt @@ -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") diff --git a/compiler/testData/codegen/box/classLiteral/java/javaReified.kt b/compiler/testData/codegen/box/classLiteral/java/javaReified.kt index 18d578ab8c1..b31ce10ad94 100644 --- a/compiler/testData/codegen/box/classLiteral/java/javaReified.kt +++ b/compiler/testData/codegen/box/classLiteral/java/javaReified.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB inline fun check(expected: String) { diff --git a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/reifiedTypeJavaClass.kt b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/reifiedTypeJavaClass.kt index 9a06b35f7c4..5bacaedc9ec 100644 --- a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/reifiedTypeJavaClass.kt +++ b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/reifiedTypeJavaClass.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/DIExample.kt b/compiler/testData/codegen/box/reified/DIExample.kt index 331d09b85e1..bae38aeff1e 100644 --- a/compiler/testData/codegen/box/reified/DIExample.kt +++ b/compiler/testData/codegen/box/reified/DIExample.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/anonymousObjectNoPropagate.kt b/compiler/testData/codegen/box/reified/anonymousObjectNoPropagate.kt index fe1f73fdde4..ee6a929817c 100644 --- a/compiler/testData/codegen/box/reified/anonymousObjectNoPropagate.kt +++ b/compiler/testData/codegen/box/reified/anonymousObjectNoPropagate.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/defaultJavaClass.kt b/compiler/testData/codegen/box/reified/defaultJavaClass.kt index 211df96bdfa..590e90c847f 100644 --- a/compiler/testData/codegen/box/reified/defaultJavaClass.kt +++ b/compiler/testData/codegen/box/reified/defaultJavaClass.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/javaClass.kt b/compiler/testData/codegen/box/reified/javaClass.kt index 9077662e7f8..b4609156199 100644 --- a/compiler/testData/codegen/box/reified/javaClass.kt +++ b/compiler/testData/codegen/box/reified/javaClass.kt @@ -1,5 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR // WITH_STDLIB diff --git a/compiler/testData/codegen/box/reified/nestedReified.kt b/compiler/testData/codegen/box/reified/nestedReified.kt index 41ec86e583d..d9f90dc7928 100644 --- a/compiler/testData/codegen/box/reified/nestedReified.kt +++ b/compiler/testData/codegen/box/reified/nestedReified.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/nonInlineableLambdaInReifiedFunction.kt b/compiler/testData/codegen/box/reified/nonInlineableLambdaInReifiedFunction.kt index 62b90aca394..5fa026d1b37 100644 --- a/compiler/testData/codegen/box/reified/nonInlineableLambdaInReifiedFunction.kt +++ b/compiler/testData/codegen/box/reified/nonInlineableLambdaInReifiedFunction.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/recursiveNonInlineableLambda.kt b/compiler/testData/codegen/box/reified/recursiveNonInlineableLambda.kt index 484cd05c0f7..6e37784b6a1 100644 --- a/compiler/testData/codegen/box/reified/recursiveNonInlineableLambda.kt +++ b/compiler/testData/codegen/box/reified/recursiveNonInlineableLambda.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/reifiedInlineFunOfObject.kt b/compiler/testData/codegen/box/reified/reifiedInlineFunOfObject.kt index f269016c30f..614856f6adf 100644 --- a/compiler/testData/codegen/box/reified/reifiedInlineFunOfObject.kt +++ b/compiler/testData/codegen/box/reified/reifiedInlineFunOfObject.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/reifiedInlineFunOfObjectWithinReified.kt b/compiler/testData/codegen/box/reified/reifiedInlineFunOfObjectWithinReified.kt index 804b1799e19..68c11556c1a 100644 --- a/compiler/testData/codegen/box/reified/reifiedInlineFunOfObjectWithinReified.kt +++ b/compiler/testData/codegen/box/reified/reifiedInlineFunOfObjectWithinReified.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reified/reifiedInlineIntoNonInlineableLambda.kt b/compiler/testData/codegen/box/reified/reifiedInlineIntoNonInlineableLambda.kt index 8ab462e7d89..fd92059db52 100644 --- a/compiler/testData/codegen/box/reified/reifiedInlineIntoNonInlineableLambda.kt +++ b/compiler/testData/codegen/box/reified/reifiedInlineIntoNonInlineableLambda.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_INLINER: IR - // WITH_STDLIB import kotlin.test.assertEquals