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.descriptors.JvmDeclarationFactory
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.descriptors.Visibilities
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.descriptors.IrBuiltIns
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.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
@@ -88,6 +91,25 @@ val IrType.erasedUpperBound: IrClass
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? {
// 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.JvmLoweredDeclarationOrigin
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.inline.coroutines.FOR_INLINE_SUFFIX
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.declarations.*
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.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
@@ -446,6 +446,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
capturedThisField: IrField?,
isStaticSuspendImpl: Boolean
) {
val backendContext = context
val invokeSuspend = context.ir.symbols.continuationImplClass.owner.functions
.single { it.name == Name.identifier(INVOKE_SUSPEND_METHOD_NAME) }
addFunctionOverride(invokeSuspend).also { function ->
@@ -481,15 +482,12 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
it.dispatchReceiver = capturedThisValue
}
irFunction.extensionReceiverParameter?.let { extensionReceiverParameter ->
it.extensionReceiver = IrConstImpl.defaultValueForType(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionReceiverParameter.type
it.extensionReceiver = extensionReceiverParameter.type.defaultValue(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext
)
}
for ((i, parameter) in irFunction.valueParameters.withIndex()) {
val defaultValueForParameter = IrConstImpl.defaultValueForType(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.type
)
it.putValueArgument(i, defaultValueForParameter)
it.putValueArgument(i, parameter.type.defaultValue(UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext))
}
if (isStaticSuspendImpl) {
it.putValueArgument(0, capturedThisValue)
@@ -501,6 +499,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
private fun createStaticSuspendImpl(irFunction: IrSimpleFunction): IrSimpleFunction {
// Create static suspend impl method.
val backendContext = context
val static = createStaticFunctionWithReceivers(
irFunction.parent,
irFunction.name.toSuspendImplementationName(),
@@ -520,12 +519,14 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
it.putValueArgument(i++, irGet(irFunction.dispatchReceiverParameter!!))
}
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) {
val defaultValueForParameter = IrConstImpl.defaultValueForType(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.type
)
val defaultValueForParameter = parameter.type.defaultValue(UNDEFINED_OFFSET, UNDEFINED_OFFSET, backendContext)
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.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.defaultValue
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.IrValueParameter
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.classOrNull
class JvmDefaultParameterInjector(context: JvmBackendContext) :
DefaultParameterInjector(context, skipInline = false, skipExternalMethods = false) {
@@ -26,15 +23,7 @@ class JvmDefaultParameterInjector(context: JvmBackendContext) :
nullConst(startOffset, endOffset, irParameter.type)
override fun nullConst(startOffset: Int, endOffset: Int, type: IrType): IrExpression {
if (type !is IrSimpleType || type.hasQuestionMark || type.classOrNull?.owner?.isInline != true)
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))
}
return type.defaultValue(startOffset, endOffset, context)
}
override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub()
@@ -1,7 +1,7 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_COROUTINES
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR, JS_IR
// IGNORE_BACKEND: JS_IR
import helpers.*
import kotlin.coroutines.*