From 2c6b5c8847da83b7d2fb368f8bc93bf458f60a21 Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Fri, 7 Aug 2020 14:02:40 +0200 Subject: [PATCH] [JVM_IR] Give temporary variable loads meaningful offsets. Temporary variable loads in when expressions had the offsets of the variable declaration. That leads to hacks during codegen for line number generation. Instead of those hacks, give the variable loads the offsets of the context in which they occur. That avoids the codegen hacks and fixes stepping behavior for more when expressions. --- .../backend/jvm/codegen/ExpressionCodegen.kt | 6 +-- .../BranchingExpressionGenerator.kt | 20 ++++++---- .../kotlin/psi2ir/intermediate/IrUtils.kt | 2 +- .../testData/debug/stepping/whenIsChecks.kt | 38 +++++++++++++++++++ .../debug/stepping/whenNullalbeSubject.kt | 24 ++++++++++++ .../IrSteppingTestGenerated.java | 12 ++++++ .../SteppingTestGenerated.java | 12 ++++++ .../testData/stepping/stepInto/whenExpr.out | 1 - 8 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/debug/stepping/whenIsChecks.kt create mode 100644 compiler/testData/debug/stepping/whenNullalbeSubject.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 3eb37a203a3..3ef33855c63 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 @@ -532,10 +532,7 @@ class ExpressionCodegen( } override fun visitGetValue(expression: IrGetValue, data: BlockInfo): PromisedValue { - // Do not generate line number information for loads from compiler-generated - // temporary variables. They do not correspond to variable loads in user code. - if (expression.symbol.owner.origin != IrDeclarationOrigin.IR_TEMPORARY_VARIABLE) - expression.markLineNumber(startOffset = true) + expression.markLineNumber(startOffset = true) val type = frameMap.typeOf(expression.symbol) mv.load(findLocalIndex(expression.symbol), type) return MaterialValue(this, type, expression.type) @@ -858,6 +855,7 @@ class ExpressionCodegen( IrTypeOperator.INSTANCEOF -> { expression.argument.accept(this, data).materializeAt(context.irBuiltIns.anyNType) val type = typeMapper.boxType(typeOperand) + if (typeOperand.isReifiedTypeParameter) { putReifiedOperationMarkerIfTypeIsReifiedParameter(typeOperand, ReifiedTypeInliner.OperationKind.IS) v.instanceOf(type) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt index 10288c9999e..43015ba3ee8 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BranchingExpressionGenerator.kt @@ -30,7 +30,7 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments import org.jetbrains.kotlin.psi2ir.deparenthesize -import org.jetbrains.kotlin.psi2ir.intermediate.defaultLoad +import org.jetbrains.kotlin.psi2ir.intermediate.loadAt import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.utils.SmartList @@ -206,12 +206,14 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta private fun generateIsPatternCondition(irSubject: IrVariable, ktCondition: KtWhenConditionIsPattern): IrExpression { val typeOperand = getOrFail(BindingContext.TYPE, ktCondition.typeReference) val irTypeOperand = typeOperand.toIrType() + val startOffset = ktCondition.startOffsetSkippingComments + val endOffset = ktCondition.endOffset val irInstanceOf = IrTypeOperatorCallImpl( - ktCondition.startOffsetSkippingComments, ktCondition.endOffset, + startOffset, endOffset, context.irBuiltIns.booleanType, IrTypeOperator.INSTANCEOF, irTypeOperand, - irSubject.defaultLoad() + irSubject.loadAt(startOffset, startOffset) ) return if (ktCondition.isNegated) primitiveOp1( @@ -227,7 +229,9 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta private fun generateInRangeCondition(irSubject: IrVariable, ktCondition: KtWhenConditionInRange): IrExpression { val inCall = statementGenerator.pregenerateCall(getResolvedCall(ktCondition.operationReference)!!) - inCall.irValueArgumentsByIndex[0] = irSubject.defaultLoad() + val startOffset = ktCondition.startOffsetSkippingComments + val endOffset = ktCondition.endOffset + inCall.irValueArgumentsByIndex[0] = irSubject.loadAt(startOffset, startOffset) val inOperator = getInfixOperator(ktCondition.operationReference.getReferencedNameElementType()) val irInCall = CallGenerator(statementGenerator).generateCall(ktCondition, inCall, inOperator) return when (inOperator) { @@ -235,7 +239,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta irInCall IrStatementOrigin.NOT_IN -> primitiveOp1( - ktCondition.startOffsetSkippingComments, ktCondition.endOffset, + startOffset, endOffset, context.irBuiltIns.booleanNotSymbol, context.irBuiltIns.booleanType, IrStatementOrigin.EXCL, @@ -248,9 +252,11 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta private fun generateEqualsCondition(irSubject: IrVariable, ktCondition: KtWhenConditionWithExpression): IrExpression { val ktExpression = ktCondition.expression val irExpression = ktExpression!!.genExpr() + val startOffset = ktCondition.startOffsetSkippingComments + val endOffset = ktCondition.endOffset return OperatorExpressionGenerator(statementGenerator).generateEquality( - ktCondition.startOffsetSkippingComments, ktCondition.endOffset, IrStatementOrigin.EQEQ, - irSubject.defaultLoad(), irExpression, + startOffset, endOffset, IrStatementOrigin.EQEQ, + irSubject.loadAt(startOffset, startOffset), irExpression, context.bindingContext[BindingContext.PRIMITIVE_NUMERIC_COMPARISON_INFO, ktExpression] ) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt index 2dfbe07e9d4..f2c4d2a225c 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/IrUtils.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl -fun IrVariable.defaultLoad(): IrExpression = +fun IrVariable.loadAt(startOffset: Int, endOffset: Int): IrExpression = IrGetValueImpl(startOffset, endOffset, type, symbol) fun CallReceiver.adjustForCallee(callee: CallableMemberDescriptor): CallReceiver = diff --git a/compiler/testData/debug/stepping/whenIsChecks.kt b/compiler/testData/debug/stepping/whenIsChecks.kt new file mode 100644 index 00000000000..180f8ea75c0 --- /dev/null +++ b/compiler/testData/debug/stepping/whenIsChecks.kt @@ -0,0 +1,38 @@ +// FILE: test.kt + +fun foo(x: Any) { + when (x) { + is Float -> + 1 + is Double -> + 2 + else -> + 3 + } +} + +fun box() { + foo(1.2f) + foo(1.2) + foo(1) +} + +// LINENUMBERS +// test.kt:15 box +// test.kt:4 foo +// test.kt:5 foo +// test.kt:6 foo +// test.kt:12 foo +// test.kt:16 box +// test.kt:4 foo +// test.kt:5 foo +// test.kt:7 foo +// test.kt:8 foo +// test.kt:12 foo +// test.kt:17 box +// test.kt:4 foo +// test.kt:5 foo +// test.kt:7 foo +// test.kt:10 foo +// test.kt:12 foo +// test.kt:18 box \ No newline at end of file diff --git a/compiler/testData/debug/stepping/whenNullalbeSubject.kt b/compiler/testData/debug/stepping/whenNullalbeSubject.kt new file mode 100644 index 00000000000..d19cca0afa9 --- /dev/null +++ b/compiler/testData/debug/stepping/whenNullalbeSubject.kt @@ -0,0 +1,24 @@ +// FILE: test.kt + +fun box() { + val a: Int? = 0 + when (a) { + 1 -> { + 1 + 1 + } + 2 -> { + 2 + 1 + } + else -> { + 0 + 0 + } + } +} + +// LINENUMBERS +// test.kt:4 box +// test.kt:5 box +// test.kt:6 box +// test.kt:9 box +// test.kt:13 box +// test.kt:16 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 9924d704a2f..05c28f3de6c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/IrSteppingTestGenerated.java @@ -427,6 +427,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest { runTest("compiler/testData/debug/stepping/whenComplicatedSubject.kt"); } + @Test + @TestMetadata("whenIsChecks.kt") + public void testWhenIsChecks() throws Exception { + runTest("compiler/testData/debug/stepping/whenIsChecks.kt"); + } + @Test @TestMetadata("whenMultiLine.kt") public void testWhenMultiLine() throws Exception { @@ -439,6 +445,12 @@ public class IrSteppingTestGenerated extends AbstractIrSteppingTest { runTest("compiler/testData/debug/stepping/whenMultiLineSubject.kt"); } + @Test + @TestMetadata("whenNullalbeSubject.kt") + public void testWhenNullalbeSubject() throws Exception { + runTest("compiler/testData/debug/stepping/whenNullalbeSubject.kt"); + } + @Test @TestMetadata("whenSubject.kt") public void testWhenSubject() 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 7ce96d3c1a4..ff9307c8026 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/debugInformation/SteppingTestGenerated.java @@ -427,6 +427,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest { runTest("compiler/testData/debug/stepping/whenComplicatedSubject.kt"); } + @Test + @TestMetadata("whenIsChecks.kt") + public void testWhenIsChecks() throws Exception { + runTest("compiler/testData/debug/stepping/whenIsChecks.kt"); + } + @Test @TestMetadata("whenMultiLine.kt") public void testWhenMultiLine() throws Exception { @@ -439,6 +445,12 @@ public class SteppingTestGenerated extends AbstractSteppingTest { runTest("compiler/testData/debug/stepping/whenMultiLineSubject.kt"); } + @Test + @TestMetadata("whenNullalbeSubject.kt") + public void testWhenNullalbeSubject() throws Exception { + runTest("compiler/testData/debug/stepping/whenNullalbeSubject.kt"); + } + @Test @TestMetadata("whenSubject.kt") public void testWhenSubject() throws Exception { diff --git a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepInto/whenExpr.out b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepInto/whenExpr.out index a36d561616e..8f65505d1de 100644 --- a/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepInto/whenExpr.out +++ b/idea/jvm-debugger/jvm-debugger-test/testData/stepping/stepInto/whenExpr.out @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR LineBreakpoint created at whenExpr.kt:5 Run Java Connected to the target VM