From d33b70af1a14149b2285a29c1d89ae9b33f50621 Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Wed, 18 Aug 2021 13:26:23 +0200 Subject: [PATCH] [JVM IR] Ensure an instruction for the line number for a break. This ensures that the debugger always has a bytecode offset for the line number of a break/continue so that you step there and so that you can set breakpoints there. The `nop` instruction is optimized out if it has no line number information. ^KT-46450 Fixed --- .../kotlin/backend/jvm/codegen/ExpressionCodegen.kt | 5 +++++ compiler/testData/debug/localVariables/tryFinally.kt | 1 + compiler/testData/debug/localVariables/tryFinally11.kt | 3 ++- compiler/testData/debug/localVariables/tryFinally12.kt | 3 ++- compiler/testData/debug/localVariables/tryFinally2.kt | 2 ++ 5 files changed, 12 insertions(+), 2 deletions(-) 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 7d486f12541..35d541f6b55 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 @@ -1159,6 +1159,11 @@ class ExpressionCodegen( override fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): PromisedValue { jump.markLineNumber(startOffset = true) + // Make sure that the line number has an instruction so that the debugger can always + // break on the break/continue. As an example, unwindBlockStack could otherwise + // generate a new line number immediately which would lead to the line number for + // the break/continue being ignored. + mv.nop() val endLabel = Label() val stackElement = unwindBlockStack(endLabel, data) { it.loop == jump.loop } if (stackElement == null) { diff --git a/compiler/testData/debug/localVariables/tryFinally.kt b/compiler/testData/debug/localVariables/tryFinally.kt index dd2acfb46f5..eda08436d14 100644 --- a/compiler/testData/debug/localVariables/tryFinally.kt +++ b/compiler/testData/debug/localVariables/tryFinally.kt @@ -23,6 +23,7 @@ fun box() { // test.kt:5 box: result:java.lang.String="":java.lang.String, x:java.lang.String="A":java.lang.String // test.kt:6 box: result:java.lang.String="":java.lang.String, x:java.lang.String="A":java.lang.String // test.kt:7 box: result:java.lang.String="":java.lang.String, x:java.lang.String="A":java.lang.String, y:java.lang.String="y":java.lang.String +// test.kt:8 box: result:java.lang.String="y":java.lang.String, x:java.lang.String="A":java.lang.String, y:java.lang.String="y":java.lang.String // test.kt:11 box: result:java.lang.String="y":java.lang.String, x:java.lang.String="A":java.lang.String // test.kt:12 box: result:java.lang.String="y":java.lang.String, x:java.lang.String="A":java.lang.String, z:java.lang.String="z":java.lang.String // test.kt:15 box: result:java.lang.String="yz":java.lang.String diff --git a/compiler/testData/debug/localVariables/tryFinally11.kt b/compiler/testData/debug/localVariables/tryFinally11.kt index 399c556413a..9ccb579fc4b 100644 --- a/compiler/testData/debug/localVariables/tryFinally11.kt +++ b/compiler/testData/debug/localVariables/tryFinally11.kt @@ -9,7 +9,7 @@ fun box(): String { } catch (e: Exception) { val y = "y" val z = "z" - break // TODO: why does the break not have a line number so we can stop on it? + break } finally { throw RuntimeException("$i") } @@ -32,5 +32,6 @@ fun box(): String { // test.kt:9 box: i:int=0:int // test.kt:10 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException // test.kt:11 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException, y:java.lang.String="y":java.lang.String +// test.kt:12 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException, y:java.lang.String="y":java.lang.String, z:java.lang.String="z":java.lang.String // test.kt:14 box: i:int=0:int // test.kt:18 box: diff --git a/compiler/testData/debug/localVariables/tryFinally12.kt b/compiler/testData/debug/localVariables/tryFinally12.kt index fab3272af13..933033865cf 100644 --- a/compiler/testData/debug/localVariables/tryFinally12.kt +++ b/compiler/testData/debug/localVariables/tryFinally12.kt @@ -9,7 +9,7 @@ fun box(): String { } catch (e: Exception) { val y = "y" val z = "z" - continue // TODO: why does the continue not have a line number so we stop here? + continue } finally { throw RuntimeException("$i") } @@ -32,5 +32,6 @@ fun box(): String { // test.kt:9 box: i:int=0:int // test.kt:10 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException // test.kt:11 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException, y:java.lang.String="y":java.lang.String +// test.kt:12 box: i:int=0:int, e:java.lang.Exception=java.lang.RuntimeException, y:java.lang.String="y":java.lang.String, z:java.lang.String="z":java.lang.String // test.kt:14 box: i:int=0:int // test.kt:18 box: diff --git a/compiler/testData/debug/localVariables/tryFinally2.kt b/compiler/testData/debug/localVariables/tryFinally2.kt index ba4b1701c39..67893453d81 100644 --- a/compiler/testData/debug/localVariables/tryFinally2.kt +++ b/compiler/testData/debug/localVariables/tryFinally2.kt @@ -23,12 +23,14 @@ fun box() { // test.kt:5 box: result:java.lang.String="":java.lang.String, x:java.lang.String="A":java.lang.String // test.kt:6 box: result:java.lang.String="":java.lang.String, x:java.lang.String="A":java.lang.String // test.kt:7 box: result:java.lang.String="":java.lang.String, x:java.lang.String="A":java.lang.String, y:java.lang.String="y":java.lang.String +// test.kt:8 box: result:java.lang.String="y":java.lang.String, x:java.lang.String="A":java.lang.String, y:java.lang.String="y":java.lang.String // test.kt:11 box: result:java.lang.String="y":java.lang.String, x:java.lang.String="A":java.lang.String // test.kt:12 box: result:java.lang.String="y":java.lang.String, x:java.lang.String="A":java.lang.String, z:java.lang.String="z":java.lang.String // test.kt:4 box: result:java.lang.String="yz":java.lang.String // test.kt:5 box: result:java.lang.String="yz":java.lang.String, x:java.lang.String="B":java.lang.String // test.kt:6 box: result:java.lang.String="yz":java.lang.String, x:java.lang.String="B":java.lang.String // test.kt:7 box: result:java.lang.String="yz":java.lang.String, x:java.lang.String="B":java.lang.String, y:java.lang.String="y":java.lang.String +// test.kt:8 box: result:java.lang.String="yzy":java.lang.String, x:java.lang.String="B":java.lang.String, y:java.lang.String="y":java.lang.String // test.kt:11 box: result:java.lang.String="yzy":java.lang.String, x:java.lang.String="B":java.lang.String // test.kt:12 box: result:java.lang.String="yzy":java.lang.String, x:java.lang.String="B":java.lang.String, z:java.lang.String="z":java.lang.String // test.kt:4 box: result:java.lang.String="yzyz":java.lang.String