diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index b0d0d71fad5..062b86e99d2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -461,9 +461,9 @@ class ExpressionCodegen( require(callee.parent is IrClass) { "Unhandled intrinsic in ExpressionCodegen: ${callee.render()}" } val callable = methodSignatureMapper.mapToCallableMethod(expression, irFunction) val callGenerator = getOrCreateCallGenerator(expression, data, callable.signature) - val isSuspensionPoint = expression.isSuspensionPoint() - if (isSuspensionPoint != SuspensionPointKind.NEVER) { + val suspensionPointKind = expression.getSuspensionPointKind() + if (suspensionPointKind != SuspensionPointKind.NEVER) { addInlineMarker(mv, isStartNotEnd = true) } @@ -490,16 +490,16 @@ class ExpressionCodegen( expression.markLineNumber(true) - if (isSuspensionPoint != SuspensionPointKind.NEVER) { - addSuspendMarker(mv, isStartNotEnd = true, isSuspensionPoint == SuspensionPointKind.NOT_INLINE) + if (suspensionPointKind != SuspensionPointKind.NEVER) { + addSuspendMarker(mv, isStartNotEnd = true, suspensionPointKind == SuspensionPointKind.NOT_INLINE) } callGenerator.genCall(callable, this, expression, isInsideCondition) val unboxedInlineClassIrType = callee.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass() - if (isSuspensionPoint != SuspensionPointKind.NEVER) { - addSuspendMarker(mv, isStartNotEnd = false, isSuspensionPoint == SuspensionPointKind.NOT_INLINE) + if (suspensionPointKind != SuspensionPointKind.NEVER) { + addSuspendMarker(mv, isStartNotEnd = false, suspensionPointKind == SuspensionPointKind.NOT_INLINE) if (unboxedInlineClassIrType != null) { generateResumePathUnboxing(mv, unboxedInlineClassIrType, typeMapper) } @@ -541,17 +541,24 @@ class ExpressionCodegen( } } - private fun IrFunctionAccessExpression.isSuspensionPoint(): SuspensionPointKind = when { - !symbol.owner.isSuspend || !irFunction.shouldContainSuspendMarkers() -> SuspensionPointKind.NEVER - // Copy-pasted bytecode blocks are not suspension points. - symbol.owner.isInline -> - if (symbol.owner.name.asString() == "suspendCoroutineUninterceptedOrReturn" && - symbol.owner.getPackageFragment()?.fqName == FqName("kotlin.coroutines.intrinsics") - ) SuspensionPointKind.ALWAYS else SuspensionPointKind.NEVER - // This includes inline lambdas, but only in functions intended for the inliner; in others, they stay as `f.invoke()`. - dispatchReceiver.isReadOfInlineLambda() -> SuspensionPointKind.NOT_INLINE - else -> SuspensionPointKind.ALWAYS - } + private fun IrFunctionAccessExpression.getSuspensionPointKind(): SuspensionPointKind = + when { + !symbol.owner.isSuspend || !irFunction.shouldContainSuspendMarkers() -> + SuspensionPointKind.NEVER + // Copy-pasted bytecode blocks are not suspension points. + symbol.owner.isInline -> + if (symbol.owner.name.asString() == "suspendCoroutineUninterceptedOrReturn" && + symbol.owner.getPackageFragment()?.fqName == FqName("kotlin.coroutines.intrinsics") + ) + SuspensionPointKind.ALWAYS + else + SuspensionPointKind.NEVER + // This includes inline lambdas, but only in functions intended for the inliner; in others, they stay as `f.invoke()`. + dispatchReceiver.isReadOfInlineLambda() -> + SuspensionPointKind.NOT_INLINE + else -> + SuspensionPointKind.ALWAYS + } override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: BlockInfo): PromisedValue { val callee = expression.symbol.owner @@ -645,7 +652,8 @@ class ExpressionCodegen( internal fun genOrGetLocal(expression: IrExpression, type: Type, parameterType: IrType, data: BlockInfo): StackValue = if (expression is IrGetValue) StackValue.local( - findLocalIndex(expression.symbol), frameMap.typeOf(expression.symbol), + findLocalIndex(expression.symbol), + frameMap.typeOf(expression.symbol), expression.symbol.owner.realType.toIrBasedKotlinType() ) else @@ -1403,7 +1411,9 @@ class ExpressionCodegen( } private fun getOrCreateCallGenerator( - element: IrFunctionAccessExpression, data: BlockInfo, signature: JvmMethodSignature + element: IrFunctionAccessExpression, + data: BlockInfo, + signature: JvmMethodSignature ): IrCallGenerator { if (!element.symbol.owner.isInlineFunctionCall(context) || classCodegen.irClass.fileParent.fileEntry is MultifileFacadeFileEntry || diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index 702f6ee6172..f62733e2466 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -55,7 +55,7 @@ class IrInlineCodegen( ) { val isInlineParameter = irValueParameter.isInlineParameter() if (isInlineParameter && argumentExpression.isInlineIrExpression()) { - val irReference = (argumentExpression as IrBlock).statements.filterIsInstance().single() + val irReference = (argumentExpression as IrBlock).statements.last() as IrFunctionReference val lambdaInfo = IrExpressionLambdaImpl(codegen, irReference) rememberClosure(parameterType, irValueParameter.index, lambdaInfo) lambdaInfo.generateLambdaBody(sourceCompiler) @@ -65,30 +65,39 @@ class IrInlineCodegen( putCapturedToLocalVal(onStack, param, ir.type.toIrBasedKotlinType()) } } else { - val kind = when (irValueParameter.origin) { - IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION -> ValueKind.DEFAULT_MASK - IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION -> ValueKind.METHOD_HANDLE_IN_DEFAULT - else -> when { - argumentExpression is IrContainerExpression && argumentExpression.origin == IrStatementOrigin.DEFAULT_VALUE -> - if (isInlineParameter) ValueKind.DEFAULT_INLINE_PARAMETER else ValueKind.DEFAULT_PARAMETER - // TODO ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND? - isInlineParameter && irValueParameter.type.isSuspendFunctionTypeOrSubtype() -> - ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER - else -> ValueKind.GENERAL - } + val kind = when { + irValueParameter.origin == IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION -> + ValueKind.DEFAULT_MASK + irValueParameter.origin == IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION -> + ValueKind.METHOD_HANDLE_IN_DEFAULT + argumentExpression is IrContainerExpression && argumentExpression.origin == IrStatementOrigin.DEFAULT_VALUE -> + if (isInlineParameter) + ValueKind.DEFAULT_INLINE_PARAMETER + else + ValueKind.DEFAULT_PARAMETER + // TODO ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_PARAMETER_CALLED_IN_SUSPEND? + isInlineParameter && irValueParameter.type.isSuspendFunctionTypeOrSubtype() -> + ValueKind.NON_INLINEABLE_ARGUMENT_FOR_INLINE_SUSPEND_PARAMETER + else -> + ValueKind.GENERAL } val onStack = when (kind) { - ValueKind.METHOD_HANDLE_IN_DEFAULT -> StackValue.constant(null, AsmTypes.OBJECT_TYPE) - ValueKind.DEFAULT_MASK -> StackValue.constant((argumentExpression as IrConst<*>).value, Type.INT_TYPE) - ValueKind.DEFAULT_PARAMETER, ValueKind.DEFAULT_INLINE_PARAMETER -> StackValue.createDefaultValue(parameterType) - // Here we replicate the old backend: reusing the locals for everything except extension receivers. - // TODO when stopping at a breakpoint placed in an inline function, arguments which reuse an existing - // local will not be visible in the debugger, so this needs to be reconsidered. - else -> if (irValueParameter.index >= 0) - codegen.genOrGetLocal(argumentExpression, parameterType, irValueParameter.type, blockInfo) - else - codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo) + ValueKind.METHOD_HANDLE_IN_DEFAULT -> + StackValue.constant(null, AsmTypes.OBJECT_TYPE) + ValueKind.DEFAULT_MASK -> + StackValue.constant((argumentExpression as IrConst<*>).value, Type.INT_TYPE) + ValueKind.DEFAULT_PARAMETER, ValueKind.DEFAULT_INLINE_PARAMETER -> + StackValue.createDefaultValue(parameterType) + else -> { + // Here we replicate the old backend: reusing the locals for everything except extension receivers. + // TODO when stopping at a breakpoint placed in an inline function, arguments which reuse an existing + // local will not be visible in the debugger, so this needs to be reconsidered. + if (irValueParameter.index >= 0) + codegen.genOrGetLocal(argumentExpression, parameterType, irValueParameter.type, blockInfo) + else + codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo) + } } val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toIrBasedKotlinType()) @@ -166,8 +175,8 @@ fun IrExpression.isInlineIrExpression() = when (this) { is IrBlock -> origin.isInlineIrExpression() is IrCallableReference<*> -> true.also { - assert((0 until valueArgumentsCount).count { getValueArgument(it) != null } == 0) { - "Expecting 0 value arguments for bounded callable reference: ${dump()}" + assert((0 until valueArgumentsCount).none { getValueArgument(it) != null }) { + "Expecting 0 value arguments for bound callable reference: ${dump()}" } } else -> false