From ef5fe0675a7cd37ea35ec80b0ccd1e5ddb0f9d5d Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 7 Jan 2020 11:46:36 +0100 Subject: [PATCH] JVM_IR: refactor suspendFunctionView fixing the check for DescriptorWithContainerSource in the process (containerSource *may* be null). --- .../backend/jvm/codegen/CoroutineCodegen.kt | 79 ++++++------------- .../inlineSuspendOfNoinlineSuspend.kt | 1 - 2 files changed, 26 insertions(+), 54 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt index 0b67e684761..08bbd674c20 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt @@ -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) } } diff --git a/compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt b/compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt index 60fd00b16dd..1e13cf2866d 100644 --- a/compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt +++ b/compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // FILE: test.kt // COMMON_COROUTINES_TEST // WITH_RUNTIME