JVM IR: do not use old KotlinTypeMapper when coercing inline classes

KotlinTypeMapper.mapInlineClassTypeAsDeclaration and
mapUnderlyingTypeOfInlineClassType invoked mapType which is defined in
descriptorBasedTypeSignatureMapping.kt and works on KotlinType.

It didn't lead to any problems, other than the fact that we were
constructing IrBasedClassDescriptor in JVM IR, and then KotlinType to
pass it to mapType, on each call to StackValue.boxInlineClass or
unboxInlineClass, which seems wasteful.

Instead of this, refactor these utilities to use type markers instead,
pass IrType and IrTypeMapper directly from JVM IR, and move the "static
type mapper" logic (which is used only in the old backend) out of
KotlinTypeMapper.
This commit is contained in:
Alexander Udalov
2021-03-31 17:03:38 +02:00
parent b5ecccb610
commit b59ac5d8f6
16 changed files with 162 additions and 98 deletions
@@ -468,7 +468,7 @@ class ExpressionCodegen(
if (isSuspensionPoint != SuspensionPointKind.NEVER) {
addSuspendMarker(mv, isStartNotEnd = false, isSuspensionPoint == SuspensionPointKind.NOT_INLINE)
if (unboxedInlineClassIrType != null) {
generateResumePathUnboxing(mv, unboxedInlineClassIrType.toIrBasedKotlinType())
generateResumePathUnboxing(mv, unboxedInlineClassIrType, typeMapper)
}
addInlineMarker(mv, isStartNotEnd = false)
}
@@ -484,7 +484,7 @@ class ExpressionCodegen(
mv.checkcast(unboxedInlineClassIrType.asmType)
}
if (irFunction.isInvokeSuspendOfContinuation()) {
StackValue.boxInlineClass(unboxedInlineClassIrType.toIrBasedKotlinType(), mv)
StackValue.boxInlineClass(unboxedInlineClassIrType, mv, typeMapper)
}
}
@@ -637,7 +637,7 @@ class ExpressionCodegen(
if (!irFunction.isInlineCallableReference) return
if (irFunction.extensionReceiverParameter?.symbol == arg.symbol) return
if (arg.type.isNullable() && arg.type.makeNotNull().unboxInlineClass().isNullable()) return
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType.toIrBasedKotlinType(), mv)
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType, mv, typeMapper)
}
// We do not mangle functions if Result is the only parameter of the function,
@@ -664,7 +664,7 @@ class ExpressionCodegen(
// Result parameter of SAM-wrapper to Java SAM is already unboxed in visitGetValue, do not unbox it anymore
if (irFunction.parentAsClass.superTypes.any { it.getClass()?.isFromJava() == true }) return
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType.toIrBasedKotlinType(), mv)
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType, mv, typeMapper)
}
private fun IrClass.isSamAdapter(): Boolean = this.superTypes.any { it.getClass()?.isFun == true }
@@ -920,7 +920,7 @@ class ExpressionCodegen(
expression.value.accept(this, data).materializeAt(returnType, returnIrType)
// In case of non-local return from suspend lambda 'materializeAt' does not box return value, box it manually.
if (isNonLocalReturn && owner.isInvokeSuspendOfLambda() && expression.value.type.isKotlinResult()) {
StackValue.boxInlineClass(expression.value.type.toIrBasedKotlinType(), mv)
StackValue.boxInlineClass(expression.value.type, mv, typeMapper)
}
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data, null)
expression.markLineNumber(startOffset = true)
@@ -40,7 +40,7 @@ import org.jetbrains.kotlin.ir.types.isKClass as isKClassImpl
import org.jetbrains.kotlin.ir.util.isSuspendFunction as isSuspendFunctionImpl
class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBase(), TypeMappingContext<JvmSignatureWriter> {
internal val typeSystem = IrTypeSystemContextImpl(context.irBuiltIns)
override val typeSystem: IrTypeSystemContext = IrTypeSystemContextImpl(context.irBuiltIns)
override val typeContext: TypeSystemCommonBackendContextForTypeMapping = IrTypeCheckerContextForTypeMapping(typeSystem, context)
override fun mapClass(classifier: ClassifierDescriptor): Type =
@@ -53,6 +53,9 @@ class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBas
error("Unknown descriptor: $classifier")
}
override fun mapTypeCommon(type: KotlinTypeMarker, mode: TypeMappingMode): Type =
mapType(type as IrType, mode)
private fun computeClassInternalName(irClass: IrClass): StringBuilder {
context.getLocalClassType(irClass)?.internalName?.let {
return StringBuilder(it)
@@ -12,15 +12,11 @@ import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.isTypeParameter
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.substitute
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.typeConstructor
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -50,12 +46,12 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
when {
isFromTypeUnboxed && !isToTypeUnboxed -> {
StackValue.boxInlineClass(erasedSourceType.toIrBasedKotlinType(), mv)
StackValue.boxInlineClass(erasedSourceType, mv, typeMapper)
return
}
!isFromTypeUnboxed && isToTypeUnboxed -> {
StackValue.unboxInlineClass(type, erasedTargetType.toIrBasedKotlinType(), mv)
StackValue.unboxInlineClass(type, erasedTargetType, mv, typeMapper)
return
}
}
@@ -64,7 +60,6 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
if (type != target || (castForReified && irType.anyTypeArgument { it.isReified })) {
StackValue.coerce(type, target, mv, type == target)
}
}
abstract fun discard()
@@ -431,20 +431,22 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
irClass.kind != ClassKind.INTERFACE && irClass.kind != ClassKind.ANNOTATION_CLASS
} ?: owner.superTypes.first()
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? {
override fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker? {
// Code in inlineClassesUtils.kt loads the property with the same name from the scope of the substituted type and takes its type.
// This code below should have the same effect.
val irClass = (this as? IrType)?.classOrNull?.owner?.takeIf { it.isInline } ?: return null
val inlineClassParameter = irClass.primaryConstructor?.valueParameters?.singleOrNull()
return inlineClassParameter?.let { parameter ->
val irClass = (this as? IrType)?.classOrNull?.owner?.takeIf { it.isInline }
return irClass?.primaryConstructor?.valueParameters?.singleOrNull()?.type
}
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? =
getUnsubstitutedUnderlyingType()?.let { type ->
// Taking only the type parameters of the class (and not its outer classes) is OK since inner classes are always top level
IrTypeSubstitutor(
irClass.typeParameters.map { it.symbol },
(this as IrType).getClass()!!.typeParameters.map { it.symbol },
(this as? IrSimpleType)?.arguments.orEmpty(),
irBuiltIns
).substitute(parameter.type)
).substitute(type as IrType)
}
}
override fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? {
if (this !is IrClassSymbol) return null