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")
|
@SinceKotlin("1.3")
|
||||||
public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
|
public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
|
||||||
completion: Continuation<T>
|
completion: Continuation<T>
|
||||||
): Continuation<Unit> =
|
): Continuation<Unit> {
|
||||||
if (this is BaseContinuationImpl)
|
val probeCompletion = probeCoroutineCreated(completion)
|
||||||
create(completion)
|
return if (this is BaseContinuationImpl)
|
||||||
|
create(probeCompletion)
|
||||||
else
|
else
|
||||||
createCoroutineFromSuspendFunction(completion) {
|
createCoroutineFromSuspendFunction(probeCompletion) {
|
||||||
(this as Function1<Continuation<T>, Any?>).invoke(it)
|
(this as Function1<Continuation<T>, Any?>).invoke(it)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates unintercepted coroutine with receiver type [R] and result type [T].
|
* 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(
|
public actual fun <R, T> (suspend R.() -> T).createCoroutineUnintercepted(
|
||||||
receiver: R,
|
receiver: R,
|
||||||
completion: Continuation<T>
|
completion: Continuation<T>
|
||||||
): Continuation<Unit> =
|
): Continuation<Unit> {
|
||||||
if (this is BaseContinuationImpl)
|
val probeCompletion = probeCoroutineCreated(completion)
|
||||||
create(receiver, completion)
|
return if (this is BaseContinuationImpl)
|
||||||
|
create(receiver, probeCompletion)
|
||||||
else {
|
else {
|
||||||
createCoroutineFromSuspendFunction(completion) {
|
createCoroutineFromSuspendFunction(probeCompletion) {
|
||||||
(this as Function2<R, Continuation<T>, Any?>).invoke(receiver, it)
|
(this as Function2<R, Continuation<T>, Any?>).invoke(receiver, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intercepts this continuation with [ContinuationInterceptor].
|
* Intercepts this continuation with [ContinuationInterceptor].
|
||||||
@@ -175,7 +179,7 @@ private inline fun <T> createCoroutineFromSuspendFunction(
|
|||||||
else
|
else
|
||||||
object : ContinuationImpl(completion as Continuation<Any?>, context) {
|
object : ContinuationImpl(completion as Continuation<Any?>, context) {
|
||||||
private var label = 0
|
private var label = 0
|
||||||
|
|
||||||
override fun invokeSuspend(result: SuccessOrFailure<Any?>): Any? =
|
override fun invokeSuspend(result: SuccessOrFailure<Any?>): Any? =
|
||||||
when (label) {
|
when (label) {
|
||||||
0 -> {
|
0 -> {
|
||||||
|
|||||||
+6
-3
@@ -13,14 +13,17 @@ import kotlin.jvm.internal.Reflection
|
|||||||
|
|
||||||
@SinceKotlin("1.3")
|
@SinceKotlin("1.3")
|
||||||
internal abstract class BaseContinuationImpl(
|
internal abstract class BaseContinuationImpl(
|
||||||
@JvmField
|
// This is `public val` so that it is private on JVM and cannot be modified by untrusted code, yet
|
||||||
protected val completion: Continuation<Any?>?
|
// it has a public getter (since even untrusted code is allowed to inspect its call stack).
|
||||||
|
public val completion: Continuation<Any?>?
|
||||||
) : Continuation<Any?>, Serializable {
|
) : Continuation<Any?>, Serializable {
|
||||||
// This implementation is final. This fact is used to unroll resumeWith recursion.
|
// This implementation is final. This fact is used to unroll resumeWith recursion.
|
||||||
public final override fun resumeWith(result: SuccessOrFailure<Any?>) {
|
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 current = this
|
||||||
var param = result
|
var param = result
|
||||||
// This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
|
|
||||||
while (true) {
|
while (true) {
|
||||||
with(current) {
|
with(current) {
|
||||||
val completion = completion!! // fail fast when trying to resume continuation without completion
|
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