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
|
package org.jetbrains.kotlin.backend.jvm.codegen
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
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.copyTypeParametersFrom
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.copyValueParametersFrom
|
||||||
import org.jetbrains.kotlin.backend.common.ir.isSuspend
|
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.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
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.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
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.*
|
||||||
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.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
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.copyTypeArgumentsFrom
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
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.createType
|
||||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.types.isUnit
|
import org.jetbrains.kotlin.ir.types.isUnit
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
|
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.kotlin.types.Variance
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
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.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
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 ||
|
if (!isSuspend || origin == JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW ||
|
||||||
origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW
|
origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW
|
||||||
) return this
|
) return this
|
||||||
context.suspendFunctionOriginalToView[this]?.let { return it }
|
return context.suspendFunctionOriginalToView[this] ?: suspendFunctionView(context)
|
||||||
return suspendFunctionView(context)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFunction {
|
private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFunction {
|
||||||
require(this.isSuspend && this is IrSimpleFunction)
|
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;)...
|
// 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;)...
|
// instead of INVOKEINTERFACE Function{N+1}.invoke(...Lkotlin/coroutines/Continuation;)...
|
||||||
val isInvokeOfNumberedSuspendFunction = (parent as? IrClass)?.defaultType?.isSuspendFunction() == true
|
val isInvokeOfNumberedSuspendFunction = (parent as? IrClass)?.defaultType?.isSuspendFunction() == true
|
||||||
// And we need to generate this function for callable references
|
// And we need to generate this function for callable references
|
||||||
val isBridgeInvokeOfCallableReference = origin == IrDeclarationOrigin.BRIDGE &&
|
val isBridgeInvokeOfCallableReference = origin == IrDeclarationOrigin.BRIDGE &&
|
||||||
(parent as? IrClass)?.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
(parent as? IrClass)?.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
||||||
val descriptor =
|
val continuationType = if (isInvokeOfNumberedSuspendFunction || isBridgeInvokeOfCallableReference)
|
||||||
if (originalDescriptor is DescriptorWithContainerSource && originalDescriptor.containerSource != null)
|
context.irBuiltIns.anyNType
|
||||||
WrappedFunctionDescriptorWithContainerSource(originalDescriptor.containerSource!!)
|
else
|
||||||
else
|
context.ir.symbols.continuationClass.createType(false, listOf(makeTypeProjection(returnType, Variance.INVARIANT)))
|
||||||
WrappedSimpleFunctionDescriptor(sourceElement = originalDescriptor.source)
|
return buildFunWithDescriptorForInlining(descriptor) {
|
||||||
return IrFunctionImpl(
|
updateFrom(this@suspendFunctionView)
|
||||||
startOffset, endOffset,
|
name = this@suspendFunctionView.name
|
||||||
if (origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE)
|
origin = if (origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE)
|
||||||
JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW
|
JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW
|
||||||
else
|
else
|
||||||
JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW,
|
JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW
|
||||||
IrSimpleFunctionSymbolImpl(descriptor),
|
returnType = context.irBuiltIns.anyNType
|
||||||
name, visibility, modality, context.irBuiltIns.anyNType,
|
}.also {
|
||||||
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
|
|
||||||
isFakeOverride = false, isOperator = false
|
|
||||||
).also {
|
|
||||||
descriptor.bind(it)
|
|
||||||
it.parent = parent
|
it.parent = parent
|
||||||
|
|
||||||
it.annotations.addAll(annotations)
|
it.annotations.addAll(annotations)
|
||||||
|
|
||||||
|
it.copyAttributes(this)
|
||||||
it.copyTypeParametersFrom(this)
|
it.copyTypeParametersFrom(this)
|
||||||
|
it.copyValueParametersFrom(this)
|
||||||
it.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(it)
|
// TODO: this should come before the default masks, if they exist; otherwise, this is not binary
|
||||||
it.extensionReceiverParameter = extensionReceiverParameter?.copyTo(it)
|
// compatible with the non-IR backend
|
||||||
|
it.addValueParameter(SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME, continuationType)
|
||||||
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()
|
|
||||||
|
|
||||||
// Add the suspend function view to the map before transforming the body to make sure
|
// 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.
|
// that recursive suspend functions do not lead to unbounded recursion at compile time.
|
||||||
context.recordSuspendFunctionView(this, it)
|
context.recordSuspendFunctionView(this, it)
|
||||||
|
|
||||||
|
val valueParametersMapping = explicitParameters.zip(it.explicitParameters).toMap()
|
||||||
it.body = body?.deepCopyWithSymbols(this)
|
it.body = body?.deepCopyWithSymbols(this)
|
||||||
it.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
|
it.body?.transformChildrenVoid(object : VariableRemapper(valueParametersMapping) {
|
||||||
override fun visitGetValue(expression: IrGetValue): IrGetValue =
|
// Do not cross class boundaries inside functions. Otherwise, callable references will try to access wrong $completion.
|
||||||
valueParametersMapping[expression.symbol.owner]?.let { newParam ->
|
override fun visitClass(declaration: IrClass): IrStatement = declaration
|
||||||
expression.run { IrGetValueImpl(startOffset, endOffset, type, newParam.symbol, origin) }
|
|
||||||
} ?: expression
|
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass): IrStatement {
|
override fun visitCall(expression: IrCall): IrExpression =
|
||||||
// Do not cross class boundaries inside functions. Otherwise, callable references will try to access wrong $completion.
|
super.visitCall(expression.createSuspendFunctionCallViewIfNeeded(context, it, callerIsInlineLambda = false))
|
||||||
return declaration
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
|
||||||
if (!expression.isSuspend) return super.visitCall(expression)
|
|
||||||
return 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
|
// FILE: test.kt
|
||||||
// COMMON_COROUTINES_TEST
|
// COMMON_COROUTINES_TEST
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
|
|||||||
Reference in New Issue
Block a user