JVM: Make coroutines spilling tests runtime
instead of bytecode text ones. Check the content of continuation object instead of bytecode, since this is less prone to changes during changes in coroutines codegen. #KT-48678
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// TARGET_BACKEND: JVM
|
||||
// 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) {
|
||||
// Should be cleanup, since there is a back edge from the rest of the loop
|
||||
saveSpilledVariables()
|
||||
val a = "a"
|
||||
saveSpilledVariables()
|
||||
blackhole(a)
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(Continuation(EmptyCoroutineContext) {
|
||||
it.getOrThrow()
|
||||
})
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
test()
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "1", "I$0" to "0", "L$0" to "null")) return "FAIL 1: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2", "I$0" to "0", "L$0" to "a")) return "FAIL 2: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "1", "I$0" to "1", "L$0" to "null")) return "FAIL 3: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2", "I$0" to "1", "L$0" to "a")) return "FAIL 4: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2", "I$0" to "1", "L$0" to "a")) return "FAIL 5: $spilledVariables"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// TARGET_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(check: Boolean) {
|
||||
if (check) {
|
||||
val a = "a1"
|
||||
saveSpilledVariables()
|
||||
blackhole(a)
|
||||
} else {
|
||||
val a = "a2"
|
||||
val b = "b2"
|
||||
saveSpilledVariables()
|
||||
blackhole(a, b)
|
||||
}
|
||||
// Cleanup both a and b, since the compiler does not know, which branch is going to executed
|
||||
saveSpilledVariables()
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(Continuation(EmptyCoroutineContext) {
|
||||
it.getOrThrow()
|
||||
})
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
test(true)
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "1", "L$0" to "a1", "L$1" to "null")) return "FAIL 1: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "3", "L$0" to "null", "L$1" to "null")) return "FAIL 2: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "3", "L$0" to "null", "L$1" to "null")) return "FAIL 3: $spilledVariables"
|
||||
|
||||
builder {
|
||||
test(false)
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "2", "L$0" to "a2", "L$1" to "b2")) return "FAIL 4: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "3", "L$0" to "null", "L$1" to "null")) return "FAIL 5: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "3", "L$0" to "null", "L$1" to "null")) return "FAIL 6: $spilledVariables"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// TARGET_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() {
|
||||
var a: String? = "a"
|
||||
saveSpilledVariables()
|
||||
blackhole(a)
|
||||
a = null
|
||||
// a is null, known at compile time, do not spill, but cleanup
|
||||
saveSpilledVariables()
|
||||
blackhole(a)
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(Continuation(EmptyCoroutineContext) {
|
||||
it.getOrThrow()
|
||||
})
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
test()
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "1", "L$0" to "a")) return "FAIL 1: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2", "L$0" to "null")) return "FAIL 2: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2", "L$0" to "null")) return "FAIL 3: $spilledVariables"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// TARGET_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() {
|
||||
val a = null
|
||||
// a is null, known at compile time, do not spill
|
||||
saveSpilledVariables()
|
||||
blackhole(a)
|
||||
saveSpilledVariables()
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(Continuation(EmptyCoroutineContext) {
|
||||
it.getOrThrow()
|
||||
})
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
test()
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "1")) return "FAIL 1: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2")) return "FAIL 2: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2")) return "FAIL 3: $spilledVariables"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// TARGET_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() {
|
||||
val a = "a"
|
||||
saveSpilledVariables()
|
||||
blackhole(a)
|
||||
// a is dead, cleanup
|
||||
saveSpilledVariables()
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(Continuation(EmptyCoroutineContext) {
|
||||
it.getOrThrow()
|
||||
})
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
test()
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "1", "L$0" to "a")) return "FAIL 1: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2", "L$0" to "null")) return "FAIL 2: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2", "L$0" to "null")) return "FAIL 3: $spilledVariables"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun main() {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// TARGET_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(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")
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "1", "L$0" to "a", "L$1" to "b")) return "FAIL 1: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "2", "L$0" to "b", "L$1" to "null")) return "FAIL 2: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "3", "L$0" to "null", "L$1" to "null")) return "FAIL 3: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "3", "L$0" to "null", "L$1" to "null")) return "FAIL 4: $spilledVariables"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun main() {
|
||||
println(box())
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// TARGET_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
|
||||
}
|
||||
|
||||
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,84 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// TARGET_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(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)
|
||||
}
|
||||
}
|
||||
// Cleanup both a and b, but c is primitive, so no need to clean it up
|
||||
saveSpilledVariables()
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(Continuation(EmptyCoroutineContext) {
|
||||
it.getOrThrow()
|
||||
})
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
test(0)
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "1", "I$0" to "0", "L$0" to "a0", "L$1" to "null")) return "FAIL 1: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "4", "I$0" to "0", "L$0" to "null", "L$1" to "null")) return "FAIL 2: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "4", "I$0" to "0", "L$0" to "null", "L$1" to "null")) return "FAIL 3: $spilledVariables"
|
||||
|
||||
builder {
|
||||
test(1)
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "2", "I$0" to "0", "L$0" to "a1", "L$1" to "b1")) return "FAIL 4: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "4", "I$0" to "0", "L$0" to "null", "L$1" to "null")) return "FAIL 5: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "4", "I$0" to "0", "L$0" to "null", "L$1" to "null")) return "FAIL 6: $spilledVariables"
|
||||
|
||||
builder {
|
||||
test(2)
|
||||
}
|
||||
if (spilledVariables != setOf("label" to "3", "I$0" to "1", "L$0" to "a2", "L$1" to "b2")) return "FAIL 7: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "4", "I$0" to "1", "L$0" to "null", "L$1" to "null")) return "FAIL 8: $spilledVariables"
|
||||
c?.resume(Unit)
|
||||
if (spilledVariables != setOf("label" to "4", "I$0" to "1", "L$0" to "null", "L$1" to "null")) return "FAIL 9: $spilledVariables"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
fun blackhole(vararg a: Any?) {}
|
||||
|
||||
suspend fun dummy() {}
|
||||
|
||||
suspend fun test() {
|
||||
for (i in 0..10) {
|
||||
// Should be cleanup, since there is a back edge from the rest of the loop
|
||||
dummy()
|
||||
val a = ""
|
||||
dummy()
|
||||
blackhole(a)
|
||||
}
|
||||
}
|
||||
|
||||
// 1 ACONST_NULL
|
||||
// 2 PUTFIELD .*L\$0 : Ljava/lang/Object;
|
||||
@@ -1,24 +0,0 @@
|
||||
fun blackhole(vararg a: Any?) {}
|
||||
|
||||
suspend fun dummy() {}
|
||||
|
||||
fun check(): Boolean = true
|
||||
|
||||
suspend fun test() {
|
||||
if (check()) {
|
||||
val a = ""
|
||||
dummy()
|
||||
blackhole(a)
|
||||
} else {
|
||||
val a = ""
|
||||
val b = ""
|
||||
dummy()
|
||||
blackhole(a, b)
|
||||
}
|
||||
// Cleanup both a and b, since the compiler does not know, which branch is going to executed
|
||||
dummy()
|
||||
}
|
||||
|
||||
// 2 ACONST_NULL
|
||||
// 3 PUTFIELD .*L\$0 : Ljava/lang/Object;
|
||||
// 2 PUTFIELD .*L\$1 : Ljava/lang/Object;
|
||||
@@ -1,18 +0,0 @@
|
||||
fun blackhole(vararg a: Any?) {}
|
||||
|
||||
suspend fun dummy() {}
|
||||
|
||||
suspend fun test() {
|
||||
var a: String? = ""
|
||||
dummy()
|
||||
blackhole(a)
|
||||
a = null
|
||||
// a is null, known at compile time, do not spill, but cleanup
|
||||
dummy()
|
||||
blackhole(a)
|
||||
}
|
||||
|
||||
// 2 PUTFIELD .*L\$0 : Ljava/lang/Object;
|
||||
|
||||
// two stores to initialize the `a` variable and one null constant to store in the spill slot.
|
||||
// 3 ACONST_NULL
|
||||
@@ -1,15 +0,0 @@
|
||||
fun blackhole(vararg a: Any?) {}
|
||||
|
||||
suspend fun dummy() {}
|
||||
|
||||
suspend fun test() {
|
||||
val a = null
|
||||
// a is null, known at compile time, do not spill
|
||||
dummy()
|
||||
blackhole(a)
|
||||
dummy()
|
||||
}
|
||||
|
||||
// before and after suspension point
|
||||
// 2 ACONST_NULL
|
||||
// 0 PUTFIELD .*L\$0 : Ljava/lang/Object;
|
||||
@@ -1,14 +0,0 @@
|
||||
fun blackhole(vararg a: Any?) {}
|
||||
|
||||
suspend fun dummy() {}
|
||||
|
||||
suspend fun test() {
|
||||
val a = ""
|
||||
dummy()
|
||||
blackhole(a)
|
||||
// a is dead, cleanup
|
||||
dummy()
|
||||
}
|
||||
|
||||
// 1 ACONST_NULL
|
||||
// 2 PUTFIELD .*L\$0 : Ljava/lang/Object;
|
||||
@@ -1,9 +0,0 @@
|
||||
suspend fun blackhole(a: Any?) {}
|
||||
|
||||
suspend fun cleanUpExample(a: String, b: String) {
|
||||
blackhole(a) // 1
|
||||
blackhole(b) // 2
|
||||
}
|
||||
|
||||
// 3 ACONST_NULL
|
||||
// 2 PUTFIELD .*L\$0 : .*;
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
val f: suspend (Int) -> Unit = { unused ->
|
||||
}
|
||||
|
||||
// 0 GETFIELD .*I\$0
|
||||
// 0 PUTFIELD .*I\$0
|
||||
@@ -1,34 +0,0 @@
|
||||
fun blackhole(vararg a: Any?) {}
|
||||
|
||||
suspend fun dummy() {}
|
||||
|
||||
fun check(): Int = 1
|
||||
|
||||
suspend fun test() {
|
||||
when (check()) {
|
||||
0 -> {
|
||||
val a = ""
|
||||
dummy()
|
||||
blackhole(a)
|
||||
}
|
||||
1 -> {
|
||||
val a = ""
|
||||
val b = ""
|
||||
dummy()
|
||||
blackhole(a, b)
|
||||
}
|
||||
else -> {
|
||||
val a = ""
|
||||
val b = ""
|
||||
val c = 1
|
||||
dummy()
|
||||
blackhole(a, b, c)
|
||||
}
|
||||
}
|
||||
// Cleanup both a and b, but c is primitive, so no need to clean it up
|
||||
dummy()
|
||||
}
|
||||
|
||||
// 2 ACONST_NULL
|
||||
// 4 PUTFIELD .*L\$0 : Ljava/lang/Object;
|
||||
// 3 PUTFIELD .*L\$1 : Ljava/lang/Object;
|
||||
Reference in New Issue
Block a user