[JVM] Split the variable range for external finally blocks in inliner

When external finally blocks are inlined none of the current locals
are in scope of the finally block.
This commit is contained in:
Mads Ager
2021-04-13 15:39:00 +02:00
committed by Mikhael Bogdanov
parent 6d9f02cfc6
commit 6095d8a7fa
10 changed files with 381 additions and 30 deletions
+55
View File
@@ -0,0 +1,55 @@
// FILE: test.kt
inline fun f(block: () -> Unit) {
try {
val z = 32
for (j in 0 until 1) {
return
}
} finally {
block()
}
}
var x: String = ""
fun compute(): String {
try {
val y = 42
for (i in 0 until 1) {
f {
return "NON_LOCAL_RETURN"
}
}
} finally {
val s2 = "OK"
x = s2 // TODO: Why is `s2` not visible here?
}
return "FAIL"
}
fun box() {
val result = compute()
val localX = x
}
// The local variables `y` and `i` are visible in the finally block with old backend.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:32 box:
// test.kt:17 compute:
// test.kt:18 compute:
// test.kt:19 compute: y:int=42:int
// test.kt:20 compute: y:int=42:int, i:int=0:int
// test.kt:4 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int
// test.kt:5 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int
// test.kt:6 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int, z$iv:int=32:int
// test.kt:7 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int, z$iv:int=32:int, j$iv:int=0:int
// test.kt:10 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int
// test.kt:21 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int, $i$a$-f-TestKt$compute$1:int=0:int
// test.kt:25 compute:
// test.kt:26 compute:
// test.kt:32 box:
// test.kt:33 box: result:java.lang.String="NON_LOCAL_RETURN":java.lang.String
// test.kt:34 box: result:java.lang.String="NON_LOCAL_RETURN":java.lang.String, localX:java.lang.String="OK":java.lang.String
+2 -6
View File
@@ -26,13 +26,9 @@ fun box() {
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 has the `a` local covering the finally block. It shouldn't.
// 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
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:25 box:
+64
View File
@@ -0,0 +1,64 @@
// FILE: test.kt
inline fun h(block: () -> Unit) {
try {
val hLocal = "hLocal"
block()
} finally {
val h = "h"
}
}
inline fun g(block: () -> Unit) {
try {
val gLocal = "gLocal"
h(block)
} finally {
val g = "g"
}
}
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 backend has `a` visible in the `compute` finally block. It shouldn't be.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:39 box:
// test.kt:24 compute:
// test.kt:25 compute:
// test.kt:26 compute: a:java.lang.String="a":java.lang.String
// test.kt:13 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int
// test.kt:14 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int
// test.kt:15 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int, gLocal$iv:java.lang.String="gLocal":java.lang.String
// test.kt:4 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int, gLocal$iv:java.lang.String="gLocal":java.lang.String, $i$f$h:int=0:int
// test.kt:5 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int, gLocal$iv:java.lang.String="gLocal":java.lang.String, $i$f$h:int=0:int
// test.kt:6 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int, gLocal$iv:java.lang.String="gLocal":java.lang.String, $i$f$h:int=0:int, hLocal$iv$iv:java.lang.String="hLocal":java.lang.String
// test.kt:27 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int, gLocal$iv:java.lang.String="gLocal":java.lang.String, $i$f$h:int=0:int, hLocal$iv$iv:java.lang.String="hLocal":java.lang.String, $i$a$-g-TestKt$compute$1:int=0:int
// test.kt:28 compute: a:java.lang.String="a":java.lang.String, $i$f$g:int=0:int, gLocal$iv:java.lang.String="gLocal":java.lang.String, $i$f$h:int=0:int, hLocal$iv$iv:java.lang.String="hLocal":java.lang.String, $i$a$-g-TestKt$compute$1:int=0:int, b:java.lang.String="b":java.lang.String
// test.kt:8 compute: a:java.lang.String="a":java.lang.String
// test.kt:17 compute: a:java.lang.String="a":java.lang.String
// test.kt:33 compute:
// test.kt:39 box:
// test.kt:40 box: result:java.lang.String="b":java.lang.String
// test.kt:41 box: result:java.lang.String="b":java.lang.String, localX:java.lang.String="OK":java.lang.String
+51
View File
@@ -0,0 +1,51 @@
// FILE: test.kt
inline fun f(block: () -> Unit) {
block()
}
var x: String = ""
fun compute(): String {
try {
val y = 42
for (i in 0 until 1) {
throw RuntimeException("$y $i")
}
} catch (e: Exception) {
val y = 32
for (j in 0 until 1) {
f {
return "NON_LOCAL_RETURN"
}
}
} finally {
x = "OK"
}
return "FAIL"
}
fun box() {
val result = compute()
val localX = x
}
// The old backend has `y` and `j` visible on the finally block.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:29 box:
// test.kt:10 compute:
// test.kt:11 compute:
// test.kt:12 compute: y:int=42:int
// test.kt:13 compute: y:int=42:int, i:int=0:int
// test.kt:15 compute:
// test.kt:16 compute: e:java.lang.Exception=java.lang.RuntimeException
// test.kt:17 compute: e:java.lang.Exception=java.lang.RuntimeException, y:int=32:int
// test.kt:18 compute: e:java.lang.Exception=java.lang.RuntimeException, y:int=32:int, j:int=0:int
// test.kt:4 compute: e:java.lang.Exception=java.lang.RuntimeException, y:int=32:int, j:int=0:int, $i$f$f:int=0:int
// test.kt:19 compute: e:java.lang.Exception=java.lang.RuntimeException, y:int=32:int, j:int=0:int, $i$f$f:int=0:int, $i$a$-f-TestKt$compute$1:int=0:int
// test.kt:23 compute: e:java.lang.Exception=java.lang.RuntimeException
// test.kt:29 box:
// test.kt:30 box: result:java.lang.String="NON_LOCAL_RETURN":java.lang.String
// test.kt:31 box: result:java.lang.String="NON_LOCAL_RETURN":java.lang.String, localX:java.lang.String="OK":java.lang.String
+54
View File
@@ -0,0 +1,54 @@
// FILE: test.kt
inline fun f(block: () -> Unit) {
try {
val z = 32
for (j in 0 until 1) {
throw RuntimeException("$z $j")
}
} catch (e: Exception) {
block()
}
}
var x: String = ""
fun compute(): String {
try {
val y = 42
for (i in 0 until 1) {
f {
return "NON_LOCAL_RETURN"
}
}
} finally {
x = "OK"
}
return "FAIL"
}
fun box() {
val result = compute()
val localX = x
}
// The old backend has `y` and `i` visible on the finally block.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:31 box:
// test.kt:17 compute:
// test.kt:18 compute:
// test.kt:19 compute: y:int=42:int
// test.kt:20 compute: y:int=42:int, i:int=0:int
// test.kt:4 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int
// test.kt:5 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int
// test.kt:6 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int, z$iv:int=32:int
// test.kt:7 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int, z$iv:int=32:int, j$iv:int=0:int
// test.kt:9 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int
// test.kt:10 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int, e$iv:java.lang.Exception=java.lang.RuntimeException
// test.kt:21 compute: y:int=42:int, i:int=0:int, $i$f$f:int=0:int, e$iv:java.lang.Exception=java.lang.RuntimeException, $i$a$-f-TestKt$compute$1:int=0:int
// test.kt:25 compute:
// test.kt:31 box:
// test.kt:32 box: result:java.lang.String="NON_LOCAL_RETURN":java.lang.String
// test.kt:33 box: result:java.lang.String="NON_LOCAL_RETURN":java.lang.String, localX:java.lang.String="OK":java.lang.String
+54
View File
@@ -0,0 +1,54 @@
// FILE: test.kt
inline fun f(block: () -> Unit) {
block()
}
var x: String = ""
fun compute(): String {
try {
try {
val y = 42
for (i in 0 until 1) {
return "NORMAL_RETURN"
}
} finally {
var s = "NOPE"
x = s
f {
return "NON_LOCAL_RETURN"
}
}
} finally {
val s2 = "OK"
x = s2 // TODO: Why is `s2` not visible here?
}
return "FAIL"
}
fun box() {
val result = compute()
val localX = x
}
// The local variables in the try and finally blocks are not removed for the finally block with the old backend.
// IGNORE_BACKEND: JVM
// LOCAL VARIABLES
// test.kt:31 box:
// test.kt:10 compute:
// test.kt:11 compute:
// test.kt:12 compute:
// test.kt:13 compute: y:int=42:int
// test.kt:14 compute: y:int=42:int, i:int=0:int
// test.kt:17 compute:
// test.kt:18 compute: s:java.lang.String="NOPE":java.lang.String
// test.kt:19 compute: s:java.lang.String="NOPE":java.lang.String
// test.kt:4 compute: s:java.lang.String="NOPE":java.lang.String, $i$f$f:int=0:int
// test.kt:20 compute: s:java.lang.String="NOPE":java.lang.String, $i$f$f:int=0:int, $i$a$-f-TestKt$compute$1:int=0:int
// test.kt:24 compute:
// test.kt:25 compute:
// test.kt:31 box:
// test.kt:32 box: result:java.lang.String="NON_LOCAL_RETURN":java.lang.String
// test.kt:33 box: result:java.lang.String="NON_LOCAL_RETURN":java.lang.String, localX:java.lang.String="OK":java.lang.String