JVM_IR: refactor suspendFunctionView
fixing the check for DescriptorWithContainerSource in the process (containerSource *may* be null).
This commit is contained in:
+26
-53
@@ -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
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
|
||||
// FILE: test.kt
|
||||
// COMMON_COROUTINES_TEST
|
||||
// WITH_RUNTIME
|
||||
|
||||
Reference in New Issue
Block a user