From 78483930bc259d12fbe1217dfa736b17aefb28b5 Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Mon, 21 Sep 2020 13:50:32 +0200 Subject: [PATCH] [JVM_IR] Fix offsets in constant propagation optimization. Loads of temporary variables that contain constants are replaced with a copy of the constant. This avoids locals loads and stores. However, the copy of the constant needs to have the offset of the load and not of the original constant. Fixes KT-41963. --- .../kotlin/backend/jvm/lower/ConstLowering.kt | 9 ++-- .../jvm/lower/JvmOptimizationLowering.kt | 2 +- .../kotlin/ir/expressions/IrConst.kt | 1 + .../kotlin/ir/expressions/impl/IrConstImpl.kt | 3 ++ .../testData/debug/stepping/whenConstant.kt | 25 +++++++++++ .../IrSteppingTestGenerated.java | 6 +++ .../SteppingTestGenerated.java | 6 +++ .../stepOver/stepOverWhenWithInline.ir.out | 43 +++++++++++++++++++ .../stepOver/stepOverWhenWithInline.kt | 5 ++- .../stepOver/stepOverWhenWithInline.out | 2 +- 10 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/debug/stepping/whenConstant.kt create mode 100644 idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.ir.out diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt index 4760a65df43..1acdba35f4d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ConstLowering.kt @@ -13,8 +13,10 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrGetField import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.types.isPrimitiveType import org.jetbrains.kotlin.ir.types.isStringClassType @@ -41,9 +43,6 @@ fun IrField.constantValue(context: JvmBackendContext? = null): IrConst<*>? { return if (implicitConst || correspondingPropertySymbol?.owner?.isConst == true) value else null } -private fun IrConst.copyWithOffsets(startOffset: Int, endOffset: Int) = - IrConstImpl(startOffset, endOffset, type, kind, value) - class ConstLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { override fun lower(irFile: IrFile) = irFile.transformChildrenVoid() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt index 7adb2dfd421..8650b71014f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt @@ -347,7 +347,7 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass // initializer with the constant initializer. val variable = expression.symbol.owner return if (isImmutableTemporaryVariableWithConstantValue(variable)) - ((variable as IrVariable).initializer!! as IrConst<*>).copy() + ((variable as IrVariable).initializer!! as IrConst<*>).copyWithOffsets(expression.startOffset, expression.endOffset) else expression } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrConst.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrConst.kt index c29a8d3422b..524c2860dcb 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrConst.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrConst.kt @@ -21,6 +21,7 @@ abstract class IrConst : IrExpression(), IrExpressionWithCopy { abstract val value: T abstract override fun copy(): IrConst + abstract fun copyWithOffsets(startOffset: Int, endOffset: Int): IrConst } sealed class IrConstKind(val asString: kotlin.String) { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrConstImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrConstImpl.kt index dd3e1e45c89..804394d553a 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrConstImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrConstImpl.kt @@ -34,6 +34,9 @@ class IrConstImpl( override fun copy(): IrConst = IrConstImpl(startOffset, endOffset, type, kind, value) + override fun copyWithOffsets(startOffset: Int, endOffset: Int) = + IrConstImpl(startOffset, endOffset, type, kind, value) + companion object { fun string(startOffset: Int, endOffset: Int, type: IrType, value: String): IrConstImpl = IrConstImpl(startOffset, endOffset, type, IrConstKind.String, value) diff --git a/compiler/testData/debug/stepping/whenConstant.kt b/compiler/testData/debug/stepping/whenConstant.kt new file mode 100644 index 00000000000..f21b7db062e --- /dev/null +++ b/compiler/testData/debug/stepping/whenConstant.kt @@ -0,0 +1,25 @@ +// FILE: test.kt + +fun box() { + when (1) { + 2 -> + "2" + 3 -> + "3" + else -> + "1" + } +} + +// JVM_IR and JVM backends have different heuristics for when to use a switch. +// JVM_IR does not use a switch in this case and therefore steps to the evaluation +// of the condition for each of the cases. + +// LINENUMBERS +// test.kt:4 box +// LINENUMBERS JVM_IR +// test.kt:5 box +// test.kt:7 box +// LINENUMBERS +// test.kt:10 box +// test.kt:12 box \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java index 1726ac8df2d..fe0a3eea11c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java @@ -433,6 +433,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest { runTest("compiler/testData/debug/stepping/whenComplicatedSubject.kt"); } + @Test + @TestMetadata("whenConstant.kt") + public void testWhenConstant() throws Exception { + runTest("compiler/testData/debug/stepping/whenConstant.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception { diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java index 1b625ae3d1c..d3290ff140d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java @@ -433,6 +433,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest { runTest("compiler/testData/debug/stepping/whenComplicatedSubject.kt"); } + @Test + @TestMetadata("whenConstant.kt") + public void testWhenConstant() throws Exception { + runTest("compiler/testData/debug/stepping/whenConstant.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception { diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.ir.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.ir.out new file mode 100644 index 00000000000..6534c7917b1 --- /dev/null +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.ir.out @@ -0,0 +1,43 @@ +LineBreakpoint created at stepOverWhenWithInline.kt:5 +Run Java +Connected to the target VM +stepOverWhenWithInline.kt:5 +stepOverWhenWithInline.kt:7 +stepOverWhenWithInline.kt:8 +stepOverWhenWithInline.kt:9 +stepOverWhenWithInline.kt:7 +stepOverWhenWithInline.kt:13 +stepOverWhenWithInline.kt:14 +stepOverWhenWithInline.kt:17 +stepOverWhenWithInline.kt:18 +stepOverWhenWithInline.kt:13 +stepOverWhenWithInline.kt:25 +stepOverWhenWithInline.kt:26 +stepOverWhenWithInline.kt:27 +stepOverWhenWithInline.kt:25 +stepOverWhenWithInline.kt:32 +stepOverWhenWithInline.kt:33 +stepOverWhenWithInline.kt:34 +stepOverWhenWithInline.kt:32 +stepOverWhenWithInline.kt:38 +stepOverWhenWithInline.kt:39 +stepOverWhenWithInline.kt:42 +stepOverWhenWithInline.kt:43 +stepOverWhenWithInline.kt:38 +stepOverWhenWithInline.kt:51 +stepOverWhenWithInline.kt:52 +stepOverWhenWithInline.kt:51 +stepOverWhenWithInline.kt:57 +stepOverWhenWithInline.kt:58 +stepOverWhenWithInline.kt:57 +stepOverWhenWithInline.kt:63 +stepOverWhenWithInline.kt:64 +stepOverWhenWithInline.kt:65 +stepOverWhenWithInline.kt:63 +stepOverWhenWithInline.kt:75 +stepOverWhenWithInline.kt:76 +stepOverWhenWithInline.kt:75 +stepOverWhenWithInline.kt:80 +Disconnected from the target VM + +Process finished with exit code 0 diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.kt b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.kt index ef8a2872c06..7e354d85655 100644 --- a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.kt +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.kt @@ -86,4 +86,7 @@ inline fun foo(f: () -> Int): Int { fun test(i: Int) = i -// STEP_OVER: 32 \ No newline at end of file +// STEP_OVER: 36 + +// JVM_IR and JVM backends have different heuristics for when to use a table switch. +// This results is minor differences in step over behavior. \ No newline at end of file diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.out index f313b395d91..37f7e46738c 100644 --- a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.out +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepOver/stepOverWhenWithInline.out @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR LineBreakpoint created at stepOverWhenWithInline.kt:5 Run Java Connected to the target VM @@ -35,6 +34,7 @@ stepOverWhenWithInline.kt:63 stepOverWhenWithInline.kt:75 stepOverWhenWithInline.kt:76 stepOverWhenWithInline.kt:75 +stepOverWhenWithInline.kt:80 Disconnected from the target VM Process finished with exit code 0