diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index dab012217e7..efe2f0675d5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -133,14 +133,13 @@ abstract class InlineCodegen( mapDefaultSignature: Boolean, typeSystem: TypeSystemCommonBackendContext, registerLineNumberAfterwards: Boolean, - isCallOfFunctionInCorrespondingDefaultDispatch: Boolean ) { var nodeAndSmap: SMAPAndMethodNode? = null try { nodeAndSmap = createInlineMethodNode( functionDescriptor, methodOwner, jvmSignature, mapDefaultSignature, typeArguments, typeSystem, state, sourceCompiler ) - endCall(inlineCall(nodeAndSmap, inlineDefaultLambdas, isCallOfFunctionInCorrespondingDefaultDispatch), registerLineNumberAfterwards) + endCall(inlineCall(nodeAndSmap, inlineDefaultLambdas), registerLineNumberAfterwards) } catch (e: CompilationException) { throw e } catch (e: InlineException) { @@ -206,7 +205,7 @@ abstract class InlineCodegen( ?: error("No stack value for continuation parameter of suspend function") } - protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean, isCallOfFunctionInCorrespondingDefaultDispatch: Boolean): InlineResult { + private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean): InlineResult { assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" } val node = nodeAndSmap.node if (inlineDefaultLambda) { @@ -234,7 +233,7 @@ abstract class InlineCodegen( val inliner = MethodInliner( node, parameters, info, FieldRemapper(null, null, parameters), isSameModule, "Method inlining " + sourceCompiler.callElementText, - SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite.takeIf { !isCallOfFunctionInCorrespondingDefaultDispatch }), + SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite), info.callSiteInfo, if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null, !isInlinedToInlineFunInKotlinRuntime() ) //with captured diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt index bc4b872df20..7fe10f21fe1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -64,7 +64,7 @@ class PsiInlineCodegen( } try { val registerLineNumber = registerLineNumberAfterwards(resolvedCall) - performInline(resolvedCall?.typeArguments?.keys?.toList(), callDefault, callDefault, codegen.typeSystem, registerLineNumber, false) + performInline(resolvedCall?.typeArguments?.keys?.toList(), callDefault, callDefault, codegen.typeSystem, registerLineNumber) } finally { state.globalInlineContext.exitFromInlining() } 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 3c28cfcd472..3f70ef2b8d3 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 @@ -1168,11 +1168,16 @@ class ExpressionCodegen( element: IrFunctionAccessExpression, data: BlockInfo, signature: JvmMethodSignature ): IrCallGenerator { if (!element.symbol.owner.isInlineFunctionCall(context) || - classCodegen.irClass.fileParent.fileEntry is MultifileFacadeFileEntry + classCodegen.irClass.fileParent.fileEntry is MultifileFacadeFileEntry || + irFunction.isInvokeSuspendOfContinuation() ) { return IrCallGenerator.DefaultCallGenerator } + if (irFunction == context.mapping.defaultArgumentsDispatchFunction[element.symbol.owner]) { + return IrInlineDefaultCodegen + } + val callee = element.symbol.owner val typeArgumentContainer = if (callee is IrConstructor) callee.parentAsClass else callee val typeArguments = 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 3f4a80d4ddc..d9a2a278ae6 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 @@ -72,14 +72,6 @@ class IrInlineCodegen( codegen: ExpressionCodegen, blockInfo: BlockInfo ) { - if (codegen.irFunction.isInvokeSuspendOfContinuation()) { - // In order to support java interop of inline suspend functions, we generate continuations for these inline suspend functions. - // These functions should behave as ordinary suspend functions, i.e. we should not inline the content of the inline function - // into continuation. - // Thus, we should put its arguments to stack. - super.genValueAndPut(irValueParameter, argumentExpression, parameterType, codegen, blockInfo) - } - val isInlineParameter = irValueParameter.isInlineParameter() if (isInlineParameter && isInlineIrExpression(argumentExpression)) { val irReference: IrFunctionReference = @@ -165,7 +157,6 @@ class IrInlineCodegen( false, codegen.typeMapper.typeSystem, registerLineNumberAfterwards = isInsideIfCondition, - isCallOfFunctionInCorrespondingDefaultDispatch = codegen.irFunction == codegen.context.mapping.defaultArgumentsDispatchFunction[function] ) } finally { state.globalInlineContext.exitFromInlining() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineDefaultCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineDefaultCodegen.kt new file mode 100644 index 00000000000..7c91c7e116d --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineDefaultCodegen.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.codegen + +import org.jetbrains.kotlin.codegen.inline.MethodBodyVisitor +import org.jetbrains.kotlin.codegen.inline.SourceMapCopier +import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression +import org.jetbrains.kotlin.ir.expressions.IrGetValue +import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Type + +/** + * A specialization of IrInlineCodegen for calls to the underlying method in a $default handler. + * Such calls are inlined verbatim in the JVM backend (see InlineCodegenForDefaultBody.kt). + * For compatibility we have to do the same thing in the JVM IR backend. + */ +object IrInlineDefaultCodegen : IrCallGenerator { + override fun genValueAndPut( + irValueParameter: IrValueParameter, + argumentExpression: IrExpression, + parameterType: Type, + codegen: ExpressionCodegen, + blockInfo: BlockInfo + ) { + // This codegen is only used for calls to the underlying function in a $default stub. + // For such calls we know that we are passing along the value parameters and reusing the same indices. + // There is no need to generate any code. + assert(argumentExpression is IrGetValue || argumentExpression is IrTypeOperatorCall && argumentExpression.argument is IrGetValue) + } + + override fun genCall(callableMethod: IrCallableMethod, codegen: ExpressionCodegen, expression: IrFunctionAccessExpression) { + val function = expression.symbol.owner + val nodeAndSmap = codegen.classCodegen.generateMethodNode(function, codegen.delegatedPropertyOptimizer) + val childSourceMapper = SourceMapCopier(codegen.smap, nodeAndSmap.classSMAP) + + val argsSize = + (Type.getArgumentsAndReturnSizes(callableMethod.asmMethod.descriptor) ushr 2) - if (function.isStatic) 1 else 0 + nodeAndSmap.node.accept(object : MethodBodyVisitor(codegen.visitor) { + override fun visitLocalVariable(name: String, desc: String, signature: String?, start: Label, end: Label, index: Int) { + // We only copy LVT entries for local variables, since we already generated entries for the method parameters, + if (index >= argsSize) super.visitLocalVariable(name, desc, signature, start, end, index) + } + + override fun visitLineNumber(line: Int, start: Label?) { + super.visitLineNumber(childSourceMapper.mapLineNumber(line), start) + } + }) + } +} diff --git a/compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt b/compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt index 0a2c9a50fc0..effaa1430bc 100644 --- a/compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt +++ b/compiler/testData/codegen/bytecodeText/defaultArguments/maskAndArgumentElimination.kt @@ -1,6 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// TODO KT-36769 Missing LVT entries for inline function (default) parameters at call site - inline fun test(p: String = "OK"): String { return p } diff --git a/compiler/testData/debug/stepping/assertion.kt b/compiler/testData/debug/stepping/assertion.kt index 3a03d0bf54d..2c064d0398f 100644 --- a/compiler/testData/debug/stepping/assertion.kt +++ b/compiler/testData/debug/stepping/assertion.kt @@ -29,12 +29,6 @@ fun box(): String { return "OK" } -// JVM_IR steps on line 15 both on the way in and on the way out -// of the massert method. This is consistent with what would -// happen if massert was not inline and we used force-step-into -// to step through the $default method. JVM only hits line 15 on -// the way in. - // LINENUMBERS // test.kt:24 box // test.kt:15 box @@ -43,9 +37,6 @@ fun box(): String { // test.kt:16 box // test.kt:17 box // test.kt:21 box -// LINENUMBERS JVM_IR -// test.kt:15 box -// LINENUMBERS // test.kt:25 box // test.kt:6 box // test.kt:3 getMASSERTIONS_ENABLED diff --git a/compiler/testData/debug/stepping/functionCallWithDefault.kt b/compiler/testData/debug/stepping/functionCallWithDefault.kt index fc4ccf2feed..d1abd01b4ac 100644 --- a/compiler/testData/debug/stepping/functionCallWithDefault.kt +++ b/compiler/testData/debug/stepping/functionCallWithDefault.kt @@ -11,11 +11,6 @@ fun foo(i: Int = 1) { inline fun bar(i: Int = 1) { } -// The JVM_IR backend has line number 11 for the inlined -// default argument handling both before and after the actual -// body of bar. That is consistent with what happens with the -// $default method in the non-inlined case. - // FORCE_STEP_INTO // LINENUMBERS // test.kt:4 box @@ -25,7 +20,4 @@ inline fun bar(i: Int = 1) { // test.kt:5 box // test.kt:11 box // test.kt:12 box -// LINENUMBERS JVM_IR -// test.kt:11 box -// LINENUMBERS // test.kt:6 box diff --git a/compiler/testData/debug/stepping/lambdaStepInlineWithDefaults.kt b/compiler/testData/debug/stepping/lambdaStepInlineWithDefaults.kt index eea017d1f00..46589cb105a 100644 --- a/compiler/testData/debug/stepping/lambdaStepInlineWithDefaults.kt +++ b/compiler/testData/debug/stepping/lambdaStepInlineWithDefaults.kt @@ -1,4 +1,4 @@ -// IGNORE_BACKEND: JVM_IR + // FILE: test.kt inline fun foo(stringMaker: () -> String = { "OK" }): String { return stringMaker() @@ -17,19 +17,6 @@ fun box(): String { return "OK" } -// The IR Backend does the following: -// test.kt:15 -// test.kt:3 -// test.kt:4 -// test.kt:3 -// test.kt:3 <--- -// test.kt:16 -// test.kt:7 -// test.kt:11 -// test.kt:8 -// test.kt:7 <--- -// test.kt:17 - // LINENUMBERS // test.kt:15 box // test.kt:3 box diff --git a/compiler/testData/debug/stepping/simpleDefaultArgWithInline.kt b/compiler/testData/debug/stepping/simpleDefaultArgWithInline.kt index 5c22debf9bf..6dde09d857e 100644 --- a/compiler/testData/debug/stepping/simpleDefaultArgWithInline.kt +++ b/compiler/testData/debug/stepping/simpleDefaultArgWithInline.kt @@ -13,18 +13,11 @@ fun box(): String { return ifoo2() } -// JVM_IR backend has the same stepping behavior as -// the non-inlined case when using force step into to step -// through $default method. JVM does not. - // FORCE_STEP_INTO // LINENUMBERS // test.kt:12 box // test.kt:3 box // test.kt:4 box -// LINENUMBERS JVM_IR -// test.kt:3 box -// LINENUMBERS // test.kt:13 box // test.kt:7 ifoo2$default (synthetic) // test.kt:8 ifoo2