Support non-tail suspend calls in JVM back-end

#KT-15597 In Progress
This commit is contained in:
Denis Zharkov
2017-01-11 16:19:38 +03:00
parent a048dde7a5
commit 0240ab0738
33 changed files with 1065 additions and 82 deletions
@@ -0,0 +1,82 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
class Controller {
var log = ""
var resumeIndex = 0
suspend fun <T> suspendWithValue(value: T): T = suspendCoroutineOrReturn { continuation ->
log += "suspend($value);"
continuation.resume(value)
SUSPENDED_MARKER
}
suspend fun suspendWithException(value: String): Unit = suspendCoroutineOrReturn { continuation ->
log += "error($value);"
continuation.resumeWithException(RuntimeException(value))
SUSPENDED_MARKER
}
}
fun test(c: suspend Controller.() -> Unit): String {
val controller = Controller()
c.startCoroutine(controller, EmptyContinuation, object: ContinuationDispatcher {
private fun dispatchResume(block: () -> Unit) {
val id = controller.resumeIndex++
controller.log += "before $id;"
block()
controller.log += "after $id;"
}
override fun <P> dispatchResume(data: P, continuation: Continuation<P>): Boolean {
dispatchResume {
continuation.resume(data)
}
return true
}
override fun dispatchResumeWithException(exception: Throwable, continuation: Continuation<*>): Boolean {
dispatchResume {
continuation.resumeWithException(exception)
}
return true
}
})
return controller.log
}
suspend fun Controller.foo() = suspendWithValue("") + suspendWithValue("O")
suspend fun Controller.test1() {
val o = foo()
val k = suspendWithValue("K")
log += "$o$k;"
}
suspend fun Controller.test2() {
try {
foo()
suspendWithException("OK")
log += "ignore;"
}
catch (e: RuntimeException) {
log += "${e.message};"
}
}
fun box(): String {
var result = test {
test1()
}
if (result != "before 0;suspend();before 1;suspend(O);before 2;before 3;suspend(K);before 4;OK;before 5;after 5;after 4;after 3;after 2;after 1;after 0;") return "fail1: $result"
result = test {
test2()
}
if (result != "before 0;suspend();before 1;suspend(O);before 2;before 3;error(OK);before 4;OK;before 5;after 5;after 4;after 3;after 2;after 1;after 0;") return "fail2: $result"
return "OK"
}
@@ -0,0 +1,112 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
class Controller {
var exception: Throwable? = null
val postponedActions = ArrayList<() -> Unit>()
suspend fun suspendWithValue(v: String): String = suspendCoroutineOrReturn { x ->
postponedActions.add {
x.resume(v)
}
SUSPENDED_MARKER
}
suspend fun suspendWithException(e: Exception): String = suspendCoroutineOrReturn { x ->
postponedActions.add {
x.resumeWithException(e)
}
SUSPENDED_MARKER
}
fun run(c: suspend Controller.() -> Unit) {
c.startCoroutine(this, handleExceptionContinuation {
exception = it
})
while (postponedActions.isNotEmpty()) {
postponedActions[0]()
postponedActions.removeAt(0)
}
}
}
fun builder(c: suspend Controller.() -> Unit) {
val controller = Controller()
controller.run(c)
if (controller.exception?.message != "OK") {
throw RuntimeException("Unexpected result: ${controller.exception?.message}")
}
}
fun commonThrow(t: Throwable) {
throw t
}
suspend fun justContinue(): Unit = suspendCoroutineOrReturn { x ->
x.resume(Unit)
SUSPENDED_MARKER
}
suspend fun Controller.test1() {
justContinue()
throw RuntimeException("OK")
}
suspend fun Controller.test2() {
justContinue()
commonThrow(RuntimeException("OK"))
}
suspend fun Controller.test3() {
justContinue()
suspendWithException(RuntimeException("OK"))
}
suspend fun Controller.test4() {
justContinue()
try {
suspendWithException(RuntimeException("fail 1"))
} catch (e: RuntimeException) {
suspendWithException(RuntimeException("OK"))
}
}
suspend fun Controller.test5() {
justContinue()
try {
suspendWithException(Exception("OK"))
} catch (e: RuntimeException) {
suspendWithException(RuntimeException("fail 3"))
throw RuntimeException("fail 4")
}
}
fun box(): String {
builder {
test1()
}
builder {
test2()
}
builder {
test3()
}
builder {
test4()
}
builder {
test5()
}
return "OK"
}
@@ -0,0 +1,32 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
x.resume(v)
SUSPENDED_MARKER
}
suspend inline fun suspendHere(crossinline block: () -> String): String {
return suspendThere(block()) + suspendThere(block())
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
var result = ""
builder {
var q = "O"
result = suspendHere {
val r = q
q = "K"
r
}
}
return result
}
@@ -0,0 +1,27 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
class A(val v: String) {
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
x.resume(v)
SUSPENDED_MARKER
}
suspend fun suspendHere(): String = suspendThere("O") + suspendThere(v)
}
fun builder(c: suspend A.() -> Unit) {
c.startCoroutine(A("K"), EmptyContinuation)
}
fun box(): String {
var result = ""
builder {
result = suspendHere()
}
return result
}
@@ -0,0 +1,28 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
x.resume(v)
SUSPENDED_MARKER
}
suspend fun suspendHere(suspend: Boolean): String {
if (!suspend) return "O"
return suspendThere("") + suspendThere("K")
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
var result = ""
builder {
result = suspendHere(false) + suspendHere(true)
}
return result
}
@@ -0,0 +1,25 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
x.resume(v)
SUSPENDED_MARKER
}
suspend fun suspendHere(): String = suspendThere("O") + suspendThere("K")
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
var result = ""
builder {
result = suspendHere()
}
return result
}
@@ -0,0 +1,31 @@
// WITH_RUNTIME
// WITH_COROUTINES
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
suspend fun suspendThere(v: String): String = suspendCoroutineOrReturn { x ->
x.resume(v)
SUSPENDED_MARKER
}
suspend fun suspendHere(): String {
val k = "K"
val x = suspendThere("O")
val y = x + suspendThere(k)
return y
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
fun box(): String {
var result = ""
builder {
result = suspendHere()
}
return result
}