From cea69e0706e3ba1d04e7ed11b8fe09b9d4250395 Mon Sep 17 00:00:00 2001 From: pyos Date: Fri, 27 Sep 2019 11:05:46 +0200 Subject: [PATCH] JVM_IR: do not generate redundant load+stores before inline calls --- .../backend/jvm/codegen/ExpressionCodegen.kt | 6 +++ .../backend/jvm/codegen/IrCallGenerator.kt | 6 --- .../backend/jvm/codegen/IrInlineCodegen.kt | 40 +++++++++---------- .../boxInline/special/unusedInlineLambda.kt | 13 ++++++ .../BlackBoxInlineCodegenTestGenerated.java | 5 +++ ...otlinAgainstInlineKotlinTestGenerated.java | 5 +++ .../IrBlackBoxInlineCodegenTestGenerated.java | 5 +++ ...otlinAgainstInlineKotlinTestGenerated.java | 5 +++ 8 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/special/unusedInlineLambda.kt 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 df27812b3e1..a8b590b7726 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 @@ -166,6 +166,12 @@ class ExpressionCodegen( return StackValue.onStack(type, irType.toKotlinType()) } + internal fun genOrGetLocal(expression: IrExpression, data: BlockInfo): StackValue = + if (expression is IrGetValue) + StackValue.local(findLocalIndex(expression.symbol), frameMap.typeOf(expression.symbol), expression.type.toKotlinType()) + else + gen(expression, typeMapper.mapType(expression.type), expression.type, data) + fun generate() { mv.visitCode() val startLabel = markNewLabel() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrCallGenerator.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrCallGenerator.kt index 6cada16b62f..f73ffc53010 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrCallGenerator.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrCallGenerator.kt @@ -16,8 +16,6 @@ package org.jetbrains.kotlin.backend.jvm.codegen -import org.jetbrains.kotlin.codegen.StackValue -import org.jetbrains.kotlin.codegen.ValueKind import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression @@ -44,9 +42,5 @@ interface IrCallGenerator { codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo) } - fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind, parameterIndex: Int, codegen: ExpressionCodegen) { - value.put(parameterType, codegen.visitor) - } - object DefaultCallGenerator : IrCallGenerator } 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 c17cbc8926e..33d8299f12a 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 @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.getArgumentsWithIr import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature @@ -72,32 +73,27 @@ class IrInlineCodegen( activeLambda = null } } else { - putValueOnStack(argumentExpression, parameterType, irValueParameter.index, blockInfo, irValueParameter.type) + val onStack = if (irValueParameter.index >= 0) + // Reuse an existing local if possible. NOTE: when stopping at a breakpoint placed + // in an inline function, arguments which reuse an existing local will not be visible + // in the debugger. + codegen.genOrGetLocal(argumentExpression, blockInfo) + else + // Do not reuse locals for receivers. While it's actually completely fine, the non-IR + // backend does not do it for internal reasons, and here we replicate the debugging + // experience. + codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo) + // TODO support default argument erasure: do nothing if the parameter is a default mask, the argument is a constant int, + // and processDefaultMaskOrMethodHandler(StackValue.constant(...), ValueKind.DEFAULT_MASK) is true. + val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toKotlinType()) + putArgumentOrCapturedToLocalVal(expectedType, onStack, -1, irValueParameter.index, ValueKind.CAPTURED) } } - override fun putValueIfNeeded( - parameterType: Type, - value: StackValue, - kind: ValueKind, - parameterIndex: Int, - codegen: ExpressionCodegen - ) { - //TODO: support default argument erasure - //if (processDefaultMaskOrMethodHandler(value, kind)) return - putArgumentOrCapturedToLocalVal(JvmKotlinType(value.type, value.kotlinType), value, -1, parameterIndex, ValueKind.CAPTURED /*kind*/) - } - private fun putCapturedValueOnStack(argumentExpression: IrExpression, valueType: Type, capturedParamIndex: Int) { - val onStack = codegen.gen(argumentExpression, valueType, argumentExpression.type, BlockInfo()) - putArgumentOrCapturedToLocalVal( - JvmKotlinType(onStack.type, onStack.kotlinType), onStack, capturedParamIndex, capturedParamIndex, ValueKind.CAPTURED - ) - } - - private fun putValueOnStack(argumentExpression: IrExpression, valueType: Type, paramIndex: Int, blockInfo: BlockInfo, irType: IrType) { - val onStack = codegen.gen(argumentExpression, valueType, irType, blockInfo) - putArgumentOrCapturedToLocalVal(JvmKotlinType(onStack.type, onStack.kotlinType), onStack, -1, paramIndex, ValueKind.CAPTURED) + val onStack = codegen.genOrGetLocal(argumentExpression, BlockInfo()) + val expectedType = JvmKotlinType(valueType, argumentExpression.type.toKotlinType()) + putArgumentOrCapturedToLocalVal(expectedType, onStack, capturedParamIndex, capturedParamIndex, ValueKind.CAPTURED) } override fun beforeValueParametersStart() { diff --git a/compiler/testData/codegen/boxInline/special/unusedInlineLambda.kt b/compiler/testData/codegen/boxInline/special/unusedInlineLambda.kt new file mode 100644 index 00000000000..edbcf28bccf --- /dev/null +++ b/compiler/testData/codegen/boxInline/special/unusedInlineLambda.kt @@ -0,0 +1,13 @@ +// FILE: 1.kt +package test + +inline fun f(g: () -> Int) {} +inline fun h(g: () -> Int) = run { f(g) } + +// FILE: 2.kt +import test.* + +fun box(): String { + h { 1 } + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 9e4fddaf99b..27b3cb9e0a9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -3412,6 +3412,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo public void testStackHeightBug() throws Exception { runTest("compiler/testData/codegen/boxInline/special/stackHeightBug.kt"); } + + @TestMetadata("unusedInlineLambda.kt") + public void testUnusedInlineLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/special/unusedInlineLambda.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/stackOnReturn") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index ac8ba7c6560..55dc9663bff 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3412,6 +3412,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi public void testStackHeightBug() throws Exception { runTest("compiler/testData/codegen/boxInline/special/stackHeightBug.kt"); } + + @TestMetadata("unusedInlineLambda.kt") + public void testUnusedInlineLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/special/unusedInlineLambda.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/stackOnReturn") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index b56c3ea364a..cdabfa2b0e1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -3412,6 +3412,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli public void testStackHeightBug() throws Exception { runTest("compiler/testData/codegen/boxInline/special/stackHeightBug.kt"); } + + @TestMetadata("unusedInlineLambda.kt") + public void testUnusedInlineLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/special/unusedInlineLambda.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/stackOnReturn") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 95295dd2b22..3098880f328 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3412,6 +3412,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC public void testStackHeightBug() throws Exception { runTest("compiler/testData/codegen/boxInline/special/stackHeightBug.kt"); } + + @TestMetadata("unusedInlineLambda.kt") + public void testUnusedInlineLambda() throws Exception { + runTest("compiler/testData/codegen/boxInline/special/unusedInlineLambda.kt"); + } } @TestMetadata("compiler/testData/codegen/boxInline/stackOnReturn")