JVM_IR: deal with inline class default values in AddContinuationLowering.

Whenever we want the default 0/null value for a type we need to
check if it is a non-nullable inline class type and produce
the right value for the underlying type.
This commit is contained in:
Mads Ager
2020-01-09 10:49:37 +01:00
committed by Ilmir Usmanov
parent 31ba2d64db
commit 4e4e57f60a
4 changed files with 37 additions and 25 deletions
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.isInlineOnly
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDeclarationFactory import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDeclarationFactory
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -20,6 +21,8 @@ import org.jetbrains.kotlin.ir.builders.Scope
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
@@ -88,6 +91,25 @@ val IrType.erasedUpperBound: IrClass
else -> throw IllegalStateException() else -> throw IllegalStateException()
} }
/**
* Get the default null/0 value for the type.
*
* This handles unboxing of non-nullable inline class types to their underlying types and produces
* a null/0 default value for the resulting type. When such unboxing takes place it ensures that
* the value is not reboxed and reunboxed by the codegen by using the unsafeCoerceIntrinsic.
*/
fun IrType.defaultValue(startOffset: Int, endOffset: Int, context: JvmBackendContext): IrExpression {
if (this !is IrSimpleType || hasQuestionMark || classOrNull?.owner?.isInline != true)
return IrConstImpl.defaultValueForType(startOffset, endOffset, this)
val underlyingType = unboxInlineClass()
val defaultValueForUnderlyingType = IrConstImpl.defaultValueForType(startOffset, endOffset, underlyingType)
return IrCallImpl(startOffset, endOffset, this, context.ir.symbols.unsafeCoerceIntrinsic).also {
it.putTypeArgument(0, underlyingType) // from
it.putTypeArgument(1, this) // to
it.putValueArgument(0, defaultValueForUnderlyingType)
}
}
fun IrDeclaration.getJvmNameFromAnnotation(): String? { fun IrDeclaration.getJvmNameFromAnnotation(): String? {
// TODO lower @JvmName? // TODO lower @JvmName?
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator
import org.jetbrains.kotlin.backend.jvm.ir.defaultValue
import org.jetbrains.kotlin.codegen.coroutines.* import org.jetbrains.kotlin.codegen.coroutines.*
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
@@ -23,7 +24,6 @@ import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
@@ -446,6 +446,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
capturedThisField: IrField?, capturedThisField: IrField?,
isStaticSuspendImpl: Boolean isStaticSuspendImpl: Boolean
) { ) {
val backendContext = context
val invokeSuspend = context.ir.symbols.continuationImplClass.owner.functions val invokeSuspend = context.ir.symbols.continuationImplClass.owner.functions
.single { it.name == Name.identifier(INVOKE_SUSPEND_METHOD_NAME) } .single { it.name == Name.identifier(INVOKE_SUSPEND_METHOD_NAME) }
addFunctionOverride(invokeSuspend).also { function -> addFunctionOverride(invokeSuspend).also { function ->
@@ -481,15 +482,12 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
it.dispatchReceiver = capturedThisValue it.dispatchReceiver = capturedThisValue
} }
irFunction.extensionReceiverParameter?.let { extensionReceiverParameter -> irFunction.extensionReceiverParameter?.let { extensionReceiverParameter ->
it.extensionReceiver = IrConstImpl.defaultValueForType( it.extensionReceiver = extensionReceiverParameter.type.defaultValue(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionReceiverParameter.type UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext
) )
} }
for ((i, parameter) in irFunction.valueParameters.withIndex()) { for ((i, parameter) in irFunction.valueParameters.withIndex()) {
val defaultValueForParameter = IrConstImpl.defaultValueForType( it.putValueArgument(i, parameter.type.defaultValue(UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext))
UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.type
)
it.putValueArgument(i, defaultValueForParameter)
} }
if (isStaticSuspendImpl) { if (isStaticSuspendImpl) {
it.putValueArgument(0, capturedThisValue) it.putValueArgument(0, capturedThisValue)
@@ -501,6 +499,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
private fun createStaticSuspendImpl(irFunction: IrSimpleFunction): IrSimpleFunction { private fun createStaticSuspendImpl(irFunction: IrSimpleFunction): IrSimpleFunction {
// Create static suspend impl method. // Create static suspend impl method.
val backendContext = context
val static = createStaticFunctionWithReceivers( val static = createStaticFunctionWithReceivers(
irFunction.parent, irFunction.parent,
irFunction.name.toSuspendImplementationName(), irFunction.name.toSuspendImplementationName(),
@@ -520,12 +519,14 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
it.putValueArgument(i++, irGet(irFunction.dispatchReceiverParameter!!)) it.putValueArgument(i++, irGet(irFunction.dispatchReceiverParameter!!))
} }
if (irFunction.extensionReceiverParameter != null) { if (irFunction.extensionReceiverParameter != null) {
it.putValueArgument(i++, irNull()) val defaultValueForParameter = irFunction.extensionReceiverParameter!!.type.defaultValue(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext
)
it.putValueArgument(i++, defaultValueForParameter)
} }
for (parameter in irFunction.valueParameters) { for (parameter in irFunction.valueParameters) {
val defaultValueForParameter = IrConstImpl.defaultValueForType( val defaultValueForParameter = parameter.type.defaultValue(UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext)
UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.type
)
it.putValueArgument(i++, defaultValueForParameter) it.putValueArgument(i++, defaultValueForParameter)
} }
}) })
@@ -7,15 +7,12 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.lower.DefaultParameterInjector import org.jetbrains.kotlin.backend.common.lower.DefaultParameterInjector
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.defaultValue
import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
class JvmDefaultParameterInjector(context: JvmBackendContext) : class JvmDefaultParameterInjector(context: JvmBackendContext) :
DefaultParameterInjector(context, skipInline = false, skipExternalMethods = false) { DefaultParameterInjector(context, skipInline = false, skipExternalMethods = false) {
@@ -26,15 +23,7 @@ class JvmDefaultParameterInjector(context: JvmBackendContext) :
nullConst(startOffset, endOffset, irParameter.type) nullConst(startOffset, endOffset, irParameter.type)
override fun nullConst(startOffset: Int, endOffset: Int, type: IrType): IrExpression { override fun nullConst(startOffset: Int, endOffset: Int, type: IrType): IrExpression {
if (type !is IrSimpleType || type.hasQuestionMark || type.classOrNull?.owner?.isInline != true) return type.defaultValue(startOffset, endOffset, context)
return super.nullConst(startOffset, endOffset, type)
val underlyingType = type.unboxInlineClass()
return IrCallImpl(startOffset, endOffset, type, context.ir.symbols.unsafeCoerceIntrinsic).apply {
putTypeArgument(0, underlyingType) // from
putTypeArgument(1, type) // to
putValueArgument(0, super.nullConst(startOffset, endOffset, underlyingType))
}
} }
override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub() override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub()
@@ -1,7 +1,7 @@
// IGNORE_BACKEND_FIR: JVM_IR // IGNORE_BACKEND_FIR: JVM_IR
// WITH_COROUTINES // WITH_COROUTINES
// WITH_RUNTIME // WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR, JS_IR // IGNORE_BACKEND: JS_IR
import helpers.* import helpers.*
import kotlin.coroutines.* import kotlin.coroutines.*