Add tests on variable spilling with debug mode enabled

#KT-48678 Fixed
This commit is contained in:
Nikita Nazarov
2022-06-29 18:45:34 +03:00
committed by Nikita Nazarov
parent 38d97d0621
commit 65bb6abae4
20 changed files with 710 additions and 0 deletions
@@ -0,0 +1,57 @@
// WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND: JVM
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun blackhole(vararg a: Any?) {}
val spilledVariables = mutableSetOf<Pair<String, String>>()
var c: Continuation<Unit>? = null
suspend fun saveSpilledVariables() = suspendCoroutineUninterceptedOrReturn<Unit> { continuation ->
spilledVariables.clear()
for (field in continuation.javaClass.declaredFields) {
if (field.name != "label" && (field.name.length != 3 || field.name[1] != '$')) continue
field.isAccessible = true
spilledVariables += field.name to "${field.get(continuation)}"
}
c = continuation
COROUTINE_SUSPENDED
}
suspend fun test() {
for (i in 0..1) {
saveSpilledVariables()
val a = "a"
saveSpilledVariables()
blackhole(a)
}
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
builder {
test()
}
val continuationName = "Continuation at BackEdgeKt\$box\$1.invokeSuspend(backEdge.kt:42)"
if (spilledVariables != setOf("label" to "1", "I$0" to "0", "L$0" to continuationName, "L$1" to "null")) return "FAIL 1: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "I$0" to "0", "L$0" to continuationName, "L$1" to "a")) return "FAIL 2: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "1", "I$0" to "1", "L$0" to continuationName, "L$1" to "a")) return "FAIL 3: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "I$0" to "1", "L$0" to continuationName, "L$1" to "a")) return "FAIL 4: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "I$0" to "1", "L$0" to continuationName, "L$1" to "a")) return "FAIL 5: $spilledVariables"
return "OK"
}
@@ -0,0 +1,76 @@
// WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND: JVM
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun blackhole(vararg a: Any?) {}
val spilledVariables = mutableSetOf<Pair<String, String>>()
var c: Continuation<Unit>? = null
suspend fun saveSpilledVariables() = suspendCoroutineUninterceptedOrReturn<Unit> { continuation ->
spilledVariables.clear()
for (field in continuation.javaClass.declaredFields) {
if (field.name != "label" && (field.name.length != 3 || field.name[1] != '$')) continue
field.isAccessible = true
val fieldValue = when (val obj = field.get(continuation)) {
is Array<*> -> obj.joinToString(prefix = "[", postfix = "]")
else -> obj
}
spilledVariables += field.name to "$fieldValue"
}
c = continuation
COROUTINE_SUSPENDED
}
suspend fun test(check: Boolean) {
if (check) {
val a = "a1"
saveSpilledVariables()
blackhole(a)
} else {
val a = "a2"
val b = "b2"
saveSpilledVariables()
blackhole(a, b)
}
saveSpilledVariables()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
builder {
test(true)
}
var continuationName = "Continuation at IfKt\$box\$1.invokeSuspend(if.kt:51)"
if (spilledVariables != setOf("label" to "1", "Z$0" to "true", "L$0" to continuationName, "L$1" to "a1", "L$2" to "null"))
return "FAIL 1: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "3", "Z$0" to "true", "L$0" to continuationName, "L$1" to "a1", "L$2" to "[a1]"))
return "FAIL 2: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "3", "Z$0" to "true", "L$0" to continuationName, "L$1" to "a1", "L$2" to "[a1]"))
return "FAIL 3: $spilledVariables"
builder {
test(false)
}
continuationName = "Continuation at IfKt\$box\$2.invokeSuspend(if.kt:65)"
if (spilledVariables != setOf("label" to "2", "Z$0" to "false", "L$0" to continuationName, "L$1" to "a2", "L$2" to "b2")) return "FAIL 4: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "3", "Z$0" to "false", "L$0" to continuationName, "L$1" to "a2", "L$2" to "b2")) return "FAIL 5: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "3", "Z$0" to "false", "L$0" to continuationName, "L$1" to "a2", "L$2" to "b2")) return "FAIL 6: $spilledVariables"
return "OK"
}
@@ -0,0 +1,57 @@
// WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND: JVM
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun blackhole(vararg a: Any?) {}
val spilledVariables = mutableSetOf<Pair<String, String>>()
var c: Continuation<Unit>? = null
suspend fun saveSpilledVariables() = suspendCoroutineUninterceptedOrReturn<Unit> { continuation ->
spilledVariables.clear()
for (field in continuation.javaClass.declaredFields) {
if (field.name != "label" && (field.name.length != 3 || field.name[1] != '$')) continue
field.isAccessible = true
val fieldValue = when (val obj = field.get(continuation)) {
is Array<*> -> obj.joinToString(prefix = "[", postfix = "]")
else -> obj
}
spilledVariables += field.name to "$fieldValue"
}
c = continuation
COROUTINE_SUSPENDED
}
suspend fun test() {
var a: String? = "a"
saveSpilledVariables()
blackhole(a)
a = null
saveSpilledVariables()
blackhole(a)
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
builder {
test()
}
val continuationName = "Continuation at NullCleanupKt\$box\$1.invokeSuspend(nullCleanup.kt:46)"
if (spilledVariables != setOf("label" to "1", "L$0" to continuationName, "L$1" to "a")) return "FAIL 1: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "L$0" to continuationName, "L$1" to "[a]")) return "FAIL 2: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "L$0" to continuationName, "L$1" to "[a]")) return "FAIL 3: $spilledVariables"
return "OK"
}
@@ -0,0 +1,55 @@
// WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND: JVM
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun blackhole(vararg a: Any?) {}
val spilledVariables = mutableSetOf<Pair<String, String>>()
var c: Continuation<Unit>? = null
suspend fun saveSpilledVariables() = suspendCoroutineUninterceptedOrReturn<Unit> { continuation ->
spilledVariables.clear()
for (field in continuation.javaClass.declaredFields) {
if (field.name != "label" && (field.name.length != 3 || field.name[1] != '$')) continue
field.isAccessible = true
val fieldValue = when (val obj = field.get(continuation)) {
is Array<*> -> obj.joinToString(prefix = "[", postfix = "]")
else -> obj
}
spilledVariables += field.name to "$fieldValue"
}
c = continuation
COROUTINE_SUSPENDED
}
suspend fun test() {
val a = null
saveSpilledVariables()
blackhole(a)
saveSpilledVariables()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
builder {
test()
}
val continuationName = "Continuation at NullNotSpillKt\$box\$1.invokeSuspend(nullNotSpill.kt:44)"
if (spilledVariables != setOf("label" to "1", "L$0" to continuationName, "L$1" to "null")) return "FAIL 1: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "L$0" to continuationName, "L$1" to "[null]")) return "FAIL 2: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "L$0" to continuationName, "L$1" to "[null]")) return "FAIL 3: $spilledVariables"
return "OK"
}
@@ -0,0 +1,59 @@
// WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND: JVM
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun blackhole(vararg a: Any?) {}
val spilledVariables = mutableSetOf<Pair<String, String>>()
var c: Continuation<Unit>? = null
suspend fun saveSpilledVariables() = suspendCoroutineUninterceptedOrReturn<Unit> { continuation ->
spilledVariables.clear()
for (field in continuation.javaClass.declaredFields) {
if (field.name != "label" && (field.name.length != 3 || field.name[1] != '$')) continue
field.isAccessible = true
val fieldValue = when (val obj = field.get(continuation)) {
is Array<*> -> obj.joinToString(prefix = "[", postfix = "]")
else -> obj
}
spilledVariables += field.name to "$fieldValue"
}
c = continuation
COROUTINE_SUSPENDED
}
suspend fun test() {
val a = "a"
saveSpilledVariables()
blackhole(a)
saveSpilledVariables()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
builder {
test()
}
val continuationName = "Continuation at SimpleKt\$box\$1.invokeSuspend(simple.kt:44)"
if (spilledVariables != setOf("label" to "1", "L$0" to continuationName, "L$1" to "a", "L$2" to "null")) return "FAIL 1: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "L$0" to continuationName, "L$1" to "a", "L$2" to "[a]")) return "FAIL 2: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "L$0" to continuationName, "L$1" to "a", "L$2" to "[a]")) return "FAIL 3: $spilledVariables"
return "OK"
}
fun main() {
println(box())
}
@@ -0,0 +1,62 @@
// WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND: JVM
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun blackhole(vararg a: Any?) {}
val spilledVariables = mutableSetOf<Pair<String, String>>()
var c: Continuation<Unit>? = null
suspend fun saveSpilledVariables() = suspendCoroutineUninterceptedOrReturn<Unit> { continuation ->
spilledVariables.clear()
for (field in continuation.javaClass.declaredFields) {
if (field.name != "label" && (field.name.length != 3 || field.name[1] != '$')) continue
field.isAccessible = true
val fieldValue = when (val obj = field.get(continuation)) {
is Array<*> -> obj.joinToString(prefix = "[", postfix = "]")
else -> obj
}
spilledVariables += field.name to "$fieldValue"
}
c = continuation
COROUTINE_SUSPENDED
}
suspend fun test(a: String, b: String) {
saveSpilledVariables()
blackhole(a)
saveSpilledVariables()
blackhole(b)
saveSpilledVariables()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
builder {
test("a", "b")
}
val continuationName = "Continuation at TwoRefsKt\$box\$1.invokeSuspend(twoRefs.kt:45)"
if (spilledVariables != setOf("label" to "1", "L$0" to "a", "L$1" to "b", "L$2" to continuationName, "L$3" to "null")) return "FAIL 1: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "2", "L$0" to "a", "L$1" to "b", "L$2" to continuationName, "L$3" to "[a]")) return "FAIL 2: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "3", "L$0" to "a", "L$1" to "b", "L$2" to continuationName, "L$3" to "[b]")) return "FAIL 3: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "3", "L$0" to "a", "L$1" to "b", "L$2" to continuationName, "L$3" to "[b]")) return "FAIL 4: $spilledVariables"
return "OK"
}
fun main() {
println(box())
}
@@ -0,0 +1,44 @@
// WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun blackhole(vararg a: Any?) {}
val spilledVariables = mutableSetOf<Pair<String, String>>()
var c: Continuation<Unit>? = null
suspend fun saveSpilledVariables() = suspendCoroutineUninterceptedOrReturn<Unit> { continuation ->
spilledVariables.clear()
for (field in continuation.javaClass.declaredFields) {
if (field.name != "label" && (field.name.length != 3 || field.name[1] != '$')) continue
field.isAccessible = true
spilledVariables += field.name to "${field.get(continuation)}"
}
c = continuation
COROUTINE_SUSPENDED
}
val test: suspend (Int) -> Unit = { unused ->
saveSpilledVariables()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
builder {
test(1)
}
if (spilledVariables != setOf("label" to "1")) return "FAIL 1: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "1")) return "FAIL 2: $spilledVariables"
return "OK"
}
@@ -0,0 +1,103 @@
// WITH_STDLIB
// FULL_JDK
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND: JVM
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun blackhole(vararg a: Any?) {}
val spilledVariables = mutableSetOf<Pair<String, String>>()
var c: Continuation<Unit>? = null
suspend fun saveSpilledVariables() = suspendCoroutineUninterceptedOrReturn<Unit> { continuation ->
spilledVariables.clear()
for (field in continuation.javaClass.declaredFields) {
if (field.name != "label" && (field.name.length != 3 || field.name[1] != '$')) continue
field.isAccessible = true
val fieldValue = when (val obj = field.get(continuation)) {
is Array<*> -> obj.joinToString(prefix = "[", postfix = "]")
else -> obj
}
spilledVariables += field.name to "$fieldValue"
}
c = continuation
COROUTINE_SUSPENDED
}
suspend fun test(check: Int) {
when (check) {
0 -> {
val a = "a0"
saveSpilledVariables()
blackhole(a)
}
1 -> {
val a = "a1"
val b = "b1"
saveSpilledVariables()
blackhole(a, b)
}
else -> {
val a = "a2"
val b = "b2"
val c = 1
saveSpilledVariables()
blackhole(a, b, c)
}
}
saveSpilledVariables()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
builder {
test(0)
}
var continuationName = "Continuation at WhenKt\$box\$1.invokeSuspend(when.kt:61)"
if (spilledVariables != setOf("label" to "1", "I$0" to "0", "I$1" to "0", "I$2" to "0", "L$0" to continuationName, "L$1" to "a0", "L$2" to "null"))
return "FAIL 1: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "4", "I$0" to "0", "I$1" to "0", "I$2" to "0", "L$0" to continuationName, "L$1" to "a0", "L$2" to "[a0]"))
return "FAIL 2: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "4", "I$0" to "0", "I$1" to "0", "I$2" to "0", "L$0" to continuationName, "L$1" to "a0", "L$2" to "[a0]"))
return "FAIL 3: $spilledVariables"
builder {
test(1)
}
continuationName = "Continuation at WhenKt\$box\$2.invokeSuspend(when.kt:75)"
if (spilledVariables != setOf("label" to "2", "I$0" to "1", "I$1" to "1", "I$2" to "0", "L$0" to continuationName, "L$1" to "a1", "L$2" to "b1"))
return "FAIL 4: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "4", "I$0" to "1", "I$1" to "1", "I$2" to "0", "L$0" to continuationName, "L$1" to "a1", "L$2" to "b1"))
return "FAIL 5: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "4", "I$0" to "1", "I$1" to "1", "I$2" to "0", "L$0" to continuationName, "L$1" to "a1", "L$2" to "b1"))
return "FAIL 6: $spilledVariables"
builder {
test(2)
}
continuationName = "Continuation at WhenKt\$box\$3.invokeSuspend(when.kt:89)"
if (spilledVariables != setOf("label" to "3", "I$0" to "2", "I$1" to "2", "I$2" to "1", "L$0" to continuationName, "L$1" to "a2", "L$2" to "b2"))
return "FAIL 7: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "4", "I$0" to "2", "I$1" to "2", "I$2" to "1", "L$0" to continuationName, "L$1" to "a2", "L$2" to "b2"))
return "FAIL 8: $spilledVariables"
c?.resume(Unit)
if (spilledVariables != setOf("label" to "4", "I$0" to "2", "I$1" to "2", "I$2" to "1", "L$0" to continuationName, "L$1" to "a2", "L$2" to "b2"))
return "FAIL 9: $spilledVariables"
return "OK"
}