[JVM_IR] Fix range of locals in connection with finally blocks.

For code such as:

```
try {
  var y = "y"
  for (i in 0 until 1) {
    return y
  }
} finally {
  println("finally")
}
```

The local variables `y` and `i` ended up covering the finally block as
well in the debugger.

This change splits the range of the locals so that they do
not cover the finally block.

This change does not change the inliner to do similar transformations,
so the range of locals is still wrong win finally blocks when inlined
into an inline function. Added a failing test to that effect.
This commit is contained in:
Mads Ager
2021-03-30 13:29:25 +02:00
committed by Mikhael Bogdanov
parent 0764a0601c
commit 6d9f02cfc6
16 changed files with 351 additions and 5 deletions
+28
View File
@@ -0,0 +1,28 @@
// FILE: test.kt
fun box() {
var result = ""
for (x in listOf("A", "B")) {
try {
val y = "y"
result += y
break
}
finally {
val z = "z"
result += z
}
}
}
// The old backend has the local y covering the finally block as well.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:3 box:
// test.kt:4 box: result:java.lang.String="":java.lang.String
// 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: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
+35
View File
@@ -0,0 +1,35 @@
// FILE: test.kt
fun box() {
var result = ""
for (x in listOf("A", "B")) {
try {
val y = "y"
result += y
continue
}
finally {
val z = "z"
result += z
}
}
}
// The old backend has the local y covering the finally block as well.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:3 box:
// test.kt:4 box: result:java.lang.String="":java.lang.String
// 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: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: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
// test.kt:15 box: result:java.lang.String="yzyz":java.lang.String
+38
View File
@@ -0,0 +1,38 @@
// FILE: test.kt
fun compute(): String {
var result = ""
for (x in listOf("A", "B")) {
try {
val y = "y"
result += y
return result
}
finally {
val z = "z"
result += z
}
}
return result
}
fun box() {
compute()
}
// The old backend has the local y covering the finally block as well.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:20 box:
// test.kt:4 compute:
// test.kt:5 compute: result:java.lang.String="":java.lang.String
// test.kt:6 compute: result:java.lang.String="":java.lang.String, x:java.lang.String="A":java.lang.String
// test.kt:7 compute: result:java.lang.String="":java.lang.String, x:java.lang.String="A":java.lang.String
// test.kt:8 compute: 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:9 compute: 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:12 compute: result:java.lang.String="y":java.lang.String, x:java.lang.String="A":java.lang.String
// test.kt:13 compute: 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:9 compute: result:java.lang.String="yz":java.lang.String, x:java.lang.String="A":java.lang.String, y:java.lang.String="y":java.lang.String
// test.kt:20 box:
// test.kt:21 box:
+49
View File
@@ -0,0 +1,49 @@
// FILE: test.kt
fun compute(): String {
var result = ""
try {
val a = "a"
try {
val b = "b"
for (i in 0 until 1) {
val e = "e"
result += b
return result
}
} finally {
val c = "c"
result += c
}
} finally {
val d = "d"
result += d
}
return result
}
fun box() {
compute()
}
// The old backend gets the local variables for finally blocks wrong.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:26 box:
// test.kt:4 compute:
// test.kt:5 compute: result:java.lang.String="":java.lang.String
// test.kt:6 compute: result:java.lang.String="":java.lang.String
// test.kt:7 compute: result:java.lang.String="":java.lang.String, a:java.lang.String="a":java.lang.String
// test.kt:8 compute: result:java.lang.String="":java.lang.String, a:java.lang.String="a":java.lang.String
// test.kt:9 compute: result:java.lang.String="":java.lang.String, a:java.lang.String="a":java.lang.String, b:java.lang.String="b":java.lang.String
// test.kt:10 compute: result:java.lang.String="":java.lang.String, a:java.lang.String="a":java.lang.String, b:java.lang.String="b":java.lang.String, i:int=0:int
// test.kt:11 compute: result:java.lang.String="":java.lang.String, a:java.lang.String="a":java.lang.String, b:java.lang.String="b":java.lang.String, i:int=0:int, e:java.lang.String="e":java.lang.String
// test.kt:12 compute: result:java.lang.String="b":java.lang.String, a:java.lang.String="a":java.lang.String, b:java.lang.String="b":java.lang.String, i:int=0:int, e:java.lang.String="e":java.lang.String
// test.kt:15 compute: result:java.lang.String="b":java.lang.String, a:java.lang.String="a":java.lang.String
// test.kt:16 compute: result:java.lang.String="b":java.lang.String, a:java.lang.String="a":java.lang.String, c:java.lang.String="c":java.lang.String
// test.kt:19 compute: result:java.lang.String="bc":java.lang.String
// test.kt:20 compute: result:java.lang.String="bc":java.lang.String, d:java.lang.String="d":java.lang.String
// test.kt:12 compute: result:java.lang.String="bcd":java.lang.String, a:java.lang.String="a":java.lang.String, b:java.lang.String="b":java.lang.String, i:int=0:int, e:java.lang.String="e":java.lang.String
// test.kt:26 box:
// test.kt:27 box:
+48
View File
@@ -0,0 +1,48 @@
// FILE: test.kt
inline fun g(block: () -> Unit) {
block()
}
var x: String? = null
fun compute(): String {
try {
for (a in listOf("a")) {
g {
for (b in listOf("b")) {
return b
}
}
}
} finally {
x = "OK"
}
return "FAIL"
}
fun box() {
val result = compute()
val localX = x
}
// JVM_IR backend correctly gets rid of the `a` local in the finally, but the inliner
// does not get rid of `b` or the inlining locals.
// JVM backend does not get rid of `a` and also the inliner does not get rid of `b`
// or the inlining locals.
// IGNORE_BACKEND: JVM_IR, JVM
// LOCAL VARIABLES
// test.kt:25 box:
// test.kt:10 compute:
// test.kt:11 compute:
// test.kt:12 compute: a:java.lang.String="a":java.lang.String
// test.kt:4 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int
// test.kt:13 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int, $i$a$-g-TestKt$compute$1:int=0:int
// test.kt:14 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int, $i$a$-g-TestKt$compute$1:int=0:int, b:java.lang.String="b":java.lang.String
// test.kt:19 compute:
// test.kt:25 box:
// test.kt:26 box: result:java.lang.String="b":java.lang.String
// test.kt:27 box: result:java.lang.String="b":java.lang.String, localX:java.lang.String="OK":java.lang.String