Coroutines debug probes
This commit is contained in:
committed by
Denis Zharkov
parent
78192ea712
commit
0b59061bfe
@@ -77,13 +77,15 @@ public actual inline fun <R, T> (suspend R.() -> T).startCoroutineUninterceptedO
|
||||
@SinceKotlin("1.3")
|
||||
public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
|
||||
completion: Continuation<T>
|
||||
): Continuation<Unit> =
|
||||
if (this is BaseContinuationImpl)
|
||||
create(completion)
|
||||
): Continuation<Unit> {
|
||||
val probeCompletion = probeCoroutineCreated(completion)
|
||||
return if (this is BaseContinuationImpl)
|
||||
create(probeCompletion)
|
||||
else
|
||||
createCoroutineFromSuspendFunction(completion) {
|
||||
createCoroutineFromSuspendFunction(probeCompletion) {
|
||||
(this as Function1<Continuation<T>, Any?>).invoke(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates unintercepted coroutine with receiver type [R] and result type [T].
|
||||
@@ -110,14 +112,16 @@ public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
|
||||
public actual fun <R, T> (suspend R.() -> T).createCoroutineUnintercepted(
|
||||
receiver: R,
|
||||
completion: Continuation<T>
|
||||
): Continuation<Unit> =
|
||||
if (this is BaseContinuationImpl)
|
||||
create(receiver, completion)
|
||||
): Continuation<Unit> {
|
||||
val probeCompletion = probeCoroutineCreated(completion)
|
||||
return if (this is BaseContinuationImpl)
|
||||
create(receiver, probeCompletion)
|
||||
else {
|
||||
createCoroutineFromSuspendFunction(completion) {
|
||||
createCoroutineFromSuspendFunction(probeCompletion) {
|
||||
(this as Function2<R, Continuation<T>, Any?>).invoke(receiver, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercepts this continuation with [ContinuationInterceptor].
|
||||
@@ -175,7 +179,7 @@ private inline fun <T> createCoroutineFromSuspendFunction(
|
||||
else
|
||||
object : ContinuationImpl(completion as Continuation<Any?>, context) {
|
||||
private var label = 0
|
||||
|
||||
|
||||
override fun invokeSuspend(result: SuccessOrFailure<Any?>): Any? =
|
||||
when (label) {
|
||||
0 -> {
|
||||
|
||||
+6
-3
@@ -13,14 +13,17 @@ import kotlin.jvm.internal.Reflection
|
||||
|
||||
@SinceKotlin("1.3")
|
||||
internal abstract class BaseContinuationImpl(
|
||||
@JvmField
|
||||
protected val completion: Continuation<Any?>?
|
||||
// This is `public val` so that it is private on JVM and cannot be modified by untrusted code, yet
|
||||
// it has a public getter (since even untrusted code is allowed to inspect its call stack).
|
||||
public val completion: Continuation<Any?>?
|
||||
) : Continuation<Any?>, Serializable {
|
||||
// This implementation is final. This fact is used to unroll resumeWith recursion.
|
||||
public final override fun resumeWith(result: SuccessOrFailure<Any?>) {
|
||||
// Invoke "resume" debug probe only once, even if previous frames are "resumed" in the loop below, too
|
||||
probeCoroutineResumed(this)
|
||||
// This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
|
||||
var current = this
|
||||
var param = result
|
||||
// This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
|
||||
while (true) {
|
||||
with(current) {
|
||||
val completion = completion!! // fail fast when trying to resume continuation without completion
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.coroutines.jvm.internal
|
||||
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
|
||||
/**
|
||||
* This probe is invoked when coroutine is being created and it can replace completion
|
||||
* with its own wrapped object to intercept completion of this coroutine.
|
||||
*
|
||||
* This probe is invoked from stdlib implementation of [createCoroutineUnintercepted] function.
|
||||
*
|
||||
* Once created, coroutine is repeatedly [resumed][probeCoroutineResumed] and [suspended][probeCoroutineSuspended],
|
||||
* until it is complete. On completion, the object that was returned by this probe is invoked.
|
||||
*
|
||||
* ```
|
||||
* +-------+ probeCoroutineCreated +-----------+
|
||||
* | START | ---------------------->| SUSPENDED |
|
||||
* +-------+ +-----------+
|
||||
* probeCoroutineResumed | ^ probeCoroutineSuspended
|
||||
* V |
|
||||
* +------------+ completion invoked +-----------+
|
||||
* | RUNNING | ------------------->| COMPLETED |
|
||||
* +------------+ +-----------+
|
||||
* ```
|
||||
*
|
||||
* While the coroutine is resumed and suspended, it is represented by the pointer to its `frame`
|
||||
* which always extends [BaseContinuationImpl] and represents a pointer to the topmost frame of the
|
||||
* coroutine. Each [BaseContinuationImpl] object has [completion][BaseContinuationImpl.completion] reference
|
||||
* that points either to another frame (extending [BaseContinuationImpl]) or to the completion object
|
||||
* that was returned by this `probeCoroutineCreated` function.
|
||||
*
|
||||
* When coroutine is [suspended][probeCoroutineSuspended], then it is later [resumed][probeCoroutineResumed]
|
||||
* with a reference to the same frame. However, while coroutine is running it can unwind its frames and
|
||||
* invoke other suspending functions, so its next suspension can happen with a different frame pointer.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
internal fun <T> probeCoroutineCreated(completion: Continuation<T>): Continuation<T> {
|
||||
/** implementation of this function is replaced by debugger */
|
||||
return completion
|
||||
}
|
||||
|
||||
/**
|
||||
* This probe is invoked when coroutine is resumed using [Continuation.resumeWith].
|
||||
*
|
||||
* This probe is invoked from stdlib implementation of [BaseContinuationImpl.resumeWith] function.
|
||||
*
|
||||
* Coroutines machinery implementation guarantees that the actual [frame] instance extends
|
||||
* [BaseContinuationImpl] class, despite the fact that the declared type of [frame]
|
||||
* parameter in this function is `Continuation<*>`. See [probeCoroutineCreated] for details.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
internal fun probeCoroutineResumed(frame: Continuation<*>) {
|
||||
/** implementation of this function is replaced by debugger */
|
||||
}
|
||||
|
||||
/**
|
||||
* This probe is invoked when coroutine is suspended using [suspendCoroutineUninterceptedOrReturn], that is
|
||||
* when the corresponding `block` returns [COROUTINE_SUSPENDED].
|
||||
*
|
||||
* This probe is invoked from compiler-generated intrinsic for [suspendCoroutineUninterceptedOrReturn] function.
|
||||
*
|
||||
* Coroutines machinery implementation guarantees that the actual [frame] instance extends
|
||||
* [BaseContinuationImpl] class, despite the fact that the declared type of [frame]
|
||||
* parameter in this function is `Continuation<*>`. See [probeCoroutineCreated] for details.
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
internal fun probeCoroutineSuspended(frame: Continuation<*>) {
|
||||
/** implementation of this function is replaced by debugger */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user