JVM_IR: refactor suspendFunctionView

fixing the check for DescriptorWithContainerSource in the process
(containerSource *may* be null).
This commit is contained in:
pyos
2020-01-07 11:46:36 +01:00
committed by Ilmir Usmanov
parent 137ef26723
commit ef5fe0675a
2 changed files with 26 additions and 54 deletions
@@ -6,9 +6,10 @@
package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.ir.copyValueParametersFrom
import org.jetbrains.kotlin.backend.common.ir.isSuspend
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.codegen.ClassBuilder
@@ -21,31 +22,24 @@ import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedFunctionDescriptorWithContainerSource
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.createType
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -141,75 +135,54 @@ internal fun IrFunction.getOrCreateSuspendFunctionViewIfNeeded(context: JvmBacke
if (!isSuspend || origin == JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW ||
origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW
) return this
context.suspendFunctionOriginalToView[this]?.let { return it }
return suspendFunctionView(context)
return context.suspendFunctionOriginalToView[this] ?: suspendFunctionView(context)
}
private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFunction {
require(this.isSuspend && this is IrSimpleFunction)
val originalDescriptor = this.descriptor
// For SuspendFunction{N}.invoke we need to generate INVOKEINTERFACE Function{N+1}.invoke(...Ljava/lang/Object;)...
// instead of INVOKEINTERFACE Function{N+1}.invoke(...Lkotlin/coroutines/Continuation;)...
val isInvokeOfNumberedSuspendFunction = (parent as? IrClass)?.defaultType?.isSuspendFunction() == true
// And we need to generate this function for callable references
val isBridgeInvokeOfCallableReference = origin == IrDeclarationOrigin.BRIDGE &&
(parent as? IrClass)?.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
val descriptor =
if (originalDescriptor is DescriptorWithContainerSource && originalDescriptor.containerSource != null)
WrappedFunctionDescriptorWithContainerSource(originalDescriptor.containerSource!!)
else
WrappedSimpleFunctionDescriptor(sourceElement = originalDescriptor.source)
return IrFunctionImpl(
startOffset, endOffset,
if (origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE)
val continuationType = if (isInvokeOfNumberedSuspendFunction || isBridgeInvokeOfCallableReference)
context.irBuiltIns.anyNType
else
context.ir.symbols.continuationClass.createType(false, listOf(makeTypeProjection(returnType, Variance.INVARIANT)))
return buildFunWithDescriptorForInlining(descriptor) {
updateFrom(this@suspendFunctionView)
name = this@suspendFunctionView.name
origin = if (origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE)
JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW
else
JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW,
IrSimpleFunctionSymbolImpl(descriptor),
name, visibility, modality, context.irBuiltIns.anyNType,
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
isFakeOverride = false, isOperator = false
).also {
descriptor.bind(it)
JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW
returnType = context.irBuiltIns.anyNType
}.also {
it.parent = parent
it.annotations.addAll(annotations)
it.copyAttributes(this)
it.copyTypeParametersFrom(this)
it.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(it)
it.extensionReceiverParameter = extensionReceiverParameter?.copyTo(it)
valueParameters.mapTo(it.valueParameters) { p -> p.copyTo(it) }
it.addValueParameter(
SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME,
if (isInvokeOfNumberedSuspendFunction || isBridgeInvokeOfCallableReference) context.irBuiltIns.anyNType
else context.ir.symbols.continuationClass.createType(false, listOf(makeTypeProjection(returnType, Variance.INVARIANT)))
)
val valueParametersMapping = explicitParameters.zip(it.explicitParameters).toMap()
it.copyValueParametersFrom(this)
// TODO: this should come before the default masks, if they exist; otherwise, this is not binary
// compatible with the non-IR backend
it.addValueParameter(SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME, continuationType)
// Add the suspend function view to the map before transforming the body to make sure
// that recursive suspend functions do not lead to unbounded recursion at compile time.
context.recordSuspendFunctionView(this, it)
val valueParametersMapping = explicitParameters.zip(it.explicitParameters).toMap()
it.body = body?.deepCopyWithSymbols(this)
it.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrGetValue =
valueParametersMapping[expression.symbol.owner]?.let { newParam ->
expression.run { IrGetValueImpl(startOffset, endOffset, type, newParam.symbol, origin) }
} ?: expression
it.body?.transformChildrenVoid(object : VariableRemapper(valueParametersMapping) {
// Do not cross class boundaries inside functions. Otherwise, callable references will try to access wrong $completion.
override fun visitClass(declaration: IrClass): IrStatement = declaration
override fun visitClass(declaration: IrClass): IrStatement {
// Do not cross class boundaries inside functions. Otherwise, callable references will try to access wrong $completion.
return declaration
}
override fun visitCall(expression: IrCall): IrExpression {
if (!expression.isSuspend) return super.visitCall(expression)
return super.visitCall(expression.createSuspendFunctionCallViewIfNeeded(context, it, callerIsInlineLambda = false))
}
override fun visitCall(expression: IrCall): IrExpression =
super.visitCall(expression.createSuspendFunctionCallViewIfNeeded(context, it, callerIsInlineLambda = false))
})
it.copyAttributes(this)
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: test.kt
// COMMON_COROUTINES_TEST
// WITH_RUNTIME