Save/restore stack in try-expressions (and statements).

Parse TryCatchBlockNode's in generated bytecode, infer stack save/restore points.
Save stack to local variables before 'try'.
Restore stack after the beginning of try-block, catch-block, and default handler.
Integrate before/after inline markers rewriting (otherwise it'll break our stacks).

 #KT-3309 Fixed
This commit is contained in:
Dmitry Petrov
2015-06-26 10:18:42 +03:00
parent 534154e20d
commit 4e42cc6b81
41 changed files with 1572 additions and 455 deletions
@@ -0,0 +1,2 @@
fun box(): String =
"O" + try { throw Exception("oops!") } catch (e: Exception) { "K" }
@@ -0,0 +1,52 @@
fun cleanup() {}
inline fun concat(x: String, y: String): String = x + y
inline fun throws() {
try {
throw Exception()
}
finally {
cleanup()
}
}
inline fun first(x: String, y: String): String = x
fun box(): String =
"" + concat(
try { "" } finally { "0" },
"" + concat(
first(
try {
try {
"O"
}
finally {
"1"
}
}
catch (e: Exception) {
throw e
}
finally {
cleanup()
},
"2"
),
first(
try {
throws()
throw Exception()
"3"
}
catch (e: Exception) {
"K"
}
finally {
cleanup()
},
"4"
)
)
)
@@ -0,0 +1,8 @@
fun foo(b: Byte, s: String, i: Int, d: Double, li: Long): String = "$b $s $i $d $li"
fun box(): String {
val test = foo(1, "abc", 1, 1.0, try { 1L } catch (e: Exception) { 10L })
if (test != "1 abc 1 1.0 1") return "Failed, test==$test"
return "OK"
}
@@ -0,0 +1,35 @@
public inline fun fails(block: () -> Unit): Throwable? {
var thrown: Throwable? = null
try {
block()
} catch (e: Throwable) {
thrown = e
}
if (thrown == null)
throw Exception("Expected an exception to be thrown")
return thrown
}
public inline fun throwIt(msg: String) {
throw Exception(msg)
}
fun box(): String {
fails {
throwIt("oops!")
}
var x = 0
try {
fails {
x = 1
}
}
catch (e: Exception) {
x = 2
}
if (x != 2) return "Failed: x==$x"
return "OK"
}
@@ -0,0 +1,2 @@
fun box(): String =
"O" + try { "K" } finally { "hmmm" }
@@ -0,0 +1,17 @@
inline fun <T> tryOrElse(f1: () -> T, f2: () -> T): T {
try {
return f1()
}
catch (e: Exception) {
return f2()
}
}
fun testIt() = "abc" + tryOrElse({ "def" }, { "oops" }) + "ghi"
fun box(): String {
val test = testIt()
if (test != "abcdefghi") return "Failed, test==$test"
return "OK"
}
@@ -0,0 +1,14 @@
inline fun <T> tryOrElse(f1: () -> T, f2: () -> T): T =
try { f1() } catch (e: Exception) { f2() }
fun testIt() =
"abc" +
tryOrElse({ try { "def" } catch(e: Exception) { "oops!" } }, { "hmmm..." }) +
"ghi"
fun box(): String {
val test = testIt()
if (test != "abcdefghi") return "Failed, test==$test"
return "OK"
}
@@ -0,0 +1,22 @@
inline fun <T> tryAndThen(f1: () -> Unit, f2: () -> Unit, f3: () -> T): T {
try {
f1()
}
catch (e: Exception) {
f2()
}
finally {
return f3()
}
}
fun testIt() = "abc" +
tryAndThen({}, {}, { "def" }) +
"ghi"
fun box(): String {
val test = testIt()
if (test != "abcdefghi") return "Failed, test==$test"
return "OK"
}
@@ -0,0 +1,20 @@
class Exception1(msg: String): Exception(msg)
class Exception2(msg: String): Exception(msg)
class Exception3(msg: String): Exception(msg)
fun box(): String =
"O" + try {
throw Exception3("K")
}
catch (e1: Exception1) {
"e1"
}
catch (e2: Exception2) {
"e2"
}
catch (e3: Exception3) {
e3.getMessage()
}
catch (e: Exception) {
"e"
}
@@ -0,0 +1,25 @@
inline fun test(s: () -> Int): Int =
try {
val i = s()
i + 10
}
finally {
0
}
fun box() : String {
test {
try {
val p = 1
return "OK"
}
catch(e: Exception) {
-2
}
finally {
-3
}
}
return "Failed"
}
@@ -0,0 +1,11 @@
fun shouldReturnFalse() : Boolean {
try {
return true
} finally {
if (true)
return false
}
}
fun box(): String =
if (shouldReturnFalse()) "Failed" else "OK"
@@ -0,0 +1,22 @@
fun shouldReturn11() : Int {
var x = 0
while (true) {
try {
if(x < 10)
x++
else
break
}
finally {
x++
}
}
return x
}
fun box(): String {
val test = shouldReturn11()
if (test != 11) return "Failed, test=$test"
return "OK"
}
@@ -0,0 +1,2 @@
fun box(): String =
"O" + try { "K" } catch (e: Exception) { "oops!" }
@@ -0,0 +1,4 @@
fun box(): String =
"" +
try { "O" } catch (e: Exception) { "1" } +
try { throw Exception("oops!") } catch (e: Exception) { "K" }
@@ -0,0 +1,19 @@
fun idiv(a: Int, b: Int): Int =
if (b == 0) throw Exception("Division by zero") else a / b
fun foo(): Int {
var sum = 0
var i = 2
while (i > -10) {
sum += try { idiv(100, i) } catch (e: Exception) { break }
i--
}
return sum
}
fun box(): String {
val test = foo()
if (test != 150) return "Failed, test=$test"
return "OK"
}
@@ -0,0 +1,17 @@
fun idiv(a: Int, b: Int): Int =
if (b == 0) throw Exception("Division by zero") else a / b
fun foo(): Int {
var sum = 0
for (i in -10 .. 10) {
sum += try { idiv(100, i) } catch (e: Exception) { continue }
}
return sum
}
fun box(): String {
val test = foo()
if (test != 0) return "Failed, test=$test"
return "OK"
}
@@ -0,0 +1,8 @@
fun box(): String =
"O" +
try {
throw Exception("oops!")
}
catch (e: Exception) {
try { "K" } catch (e: Exception) { "2" }
}
@@ -0,0 +1,10 @@
class MyException(message: String): Exception(message)
fun box(): String =
"O" +
try {
try { throw Exception("oops!") } catch (mye: MyException) { "1" }
}
catch (e: Exception) {
"K"
}
@@ -0,0 +1,17 @@
inline fun catchAll(x: String, block: () -> Unit): String {
try {
block()
} catch (e: Throwable) {
}
return x
}
inline fun throwIt(msg: String) {
throw Exception(msg)
}
inline fun bar(x: String): String =
x + catchAll("") { throwIt("oops!") }
fun box(): String =
bar("OK")