Skip to content

Commit 8b28edd

Browse files
committed
Display artificial stack frames as calls to functions instead of text (#2461)
Fixes #2291
1 parent a6b17dc commit 8b28edd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+177
-143
lines changed

docs/images/after.png

-134 KB
Loading

docs/images/before.png

-61.8 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
/* This package name is like this so that
6+
1) the artificial stack frames look pretty, and
7+
2) the IDE reliably navigates to this file. */
8+
package _COROUTINE
9+
10+
/**
11+
* A collection of artificial stack trace elements to be included in stack traces by the coroutines machinery.
12+
*
13+
* There are typically two ways in which one can encounter an artificial stack frame:
14+
* 1. By using the debug mode, via the stacktrace recovery mechanism; see
15+
* [stacktrace recovery](https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/topics/debugging.md#stacktrace-recovery)
16+
* documentation. The usual way to enable the debug mode is with the [kotlinx.coroutines.DEBUG_PROPERTY_NAME] system
17+
* property.
18+
* 2. By looking at the output of DebugProbes; see the
19+
* [kotlinx-coroutines-debug](https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-debug) module.
20+
*/
21+
internal class ArtificialStackFrames {
22+
/**
23+
* Returns an artificial stack trace element denoting the boundary between coroutine creation and its execution.
24+
*
25+
* Appearance of this function in stack traces does not mean that it was called. Instead, it is used as a marker
26+
* that separates the part of the stack trace with the code executed in a coroutine from the stack trace of the code
27+
* that launched the coroutine.
28+
*
29+
* In earlier versions of kotlinx-coroutines, this was displayed as "(Coroutine creation stacktrace)", which caused
30+
* problems for tooling that processes stack traces: https://github.com/Kotlin/kotlinx.coroutines/issues/2291
31+
*
32+
* Note that presence of this marker in a stack trace implies that coroutine creation stack traces were enabled.
33+
*/
34+
fun coroutineCreation(): StackTraceElement = Exception().artificialFrame(_CREATION::class.java.simpleName)
35+
36+
/**
37+
* Returns an artificial stack trace element denoting a coroutine boundary.
38+
*
39+
* Appearance of this function in stack traces does not mean that it was called. Instead, when one coroutine invokes
40+
* another, this is used as a marker in the stack trace to denote where the execution of one coroutine ends and that
41+
* of another begins.
42+
*
43+
* In earlier versions of kotlinx-coroutines, this was displayed as "(Coroutine boundary)", which caused
44+
* problems for tooling that processes stack traces: https://github.com/Kotlin/kotlinx.coroutines/issues/2291
45+
*/
46+
fun coroutineBoundary(): StackTraceElement = Exception().artificialFrame(_BOUNDARY::class.java.simpleName)
47+
}
48+
49+
// These are needed for the IDE navigation to detect that this file does contain the definition.
50+
private class _CREATION
51+
private class _BOUNDARY
52+
53+
internal val ARTIFICIAL_FRAME_PACKAGE_NAME = "_COROUTINE"
54+
55+
/**
56+
* Forms an artificial stack frame with the given class name.
57+
*
58+
* It consists of the following parts:
59+
* 1. The package name, it seems, is needed for the IDE to detect stack trace elements reliably. It is `_COROUTINE` since
60+
* this is a valid identifier.
61+
* 2. Class names represents what type of artificial frame this is.
62+
* 3. The method name is `_`. The methods not being present in class definitions does not seem to affect navigation.
63+
*/
64+
private fun Throwable.artificialFrame(name: String): StackTraceElement =
65+
with(stackTrace[0]) { StackTraceElement(ARTIFICIAL_FRAME_PACKAGE_NAME + "." + name, "_", fileName, lineNumber) }

kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt

+16-18
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package kotlinx.coroutines.debug.internal
66

77
import kotlinx.atomicfu.*
88
import kotlinx.coroutines.*
9-
import kotlinx.coroutines.internal.*
109
import kotlinx.coroutines.internal.ScopeCoroutine
1110
import java.io.*
1211
import java.lang.StackTraceElement
@@ -17,10 +16,10 @@ import kotlin.concurrent.*
1716
import kotlin.coroutines.*
1817
import kotlin.coroutines.jvm.internal.CoroutineStackFrame
1918
import kotlin.synchronized
20-
import kotlinx.coroutines.internal.artificialFrame as createArtificialFrame // IDEA bug workaround
19+
import _COROUTINE.ArtificialStackFrames
2120

2221
internal object DebugProbesImpl {
23-
private const val ARTIFICIAL_FRAME_MESSAGE = "Coroutine creation stacktrace"
22+
private val ARTIFICIAL_FRAME = ArtificialStackFrames().coroutineCreation()
2423
private val dateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
2524

2625
private var weakRefCleanerThread: Thread? = null
@@ -298,7 +297,7 @@ internal object DebugProbesImpl {
298297
info.state
299298
out.print("\n\nCoroutine ${owner.delegate}, state: $state")
300299
if (observedStackTrace.isEmpty()) {
301-
out.print("\n\tat ${createArtificialFrame(ARTIFICIAL_FRAME_MESSAGE)}")
300+
out.print("\n\tat $ARTIFICIAL_FRAME")
302301
printStackTrace(out, info.creationStackTrace)
303302
} else {
304303
printStackTrace(out, enhancedStackTrace)
@@ -500,15 +499,17 @@ internal object DebugProbesImpl {
500499
return createOwner(completion, frame)
501500
}
502501

503-
private fun List<StackTraceElement>.toStackTraceFrame(): StackTraceFrame? =
504-
foldRight<StackTraceElement, StackTraceFrame?>(null) { frame, acc ->
505-
StackTraceFrame(acc, frame)
506-
}
502+
private fun List<StackTraceElement>.toStackTraceFrame(): StackTraceFrame =
503+
StackTraceFrame(
504+
foldRight<StackTraceElement, StackTraceFrame?>(null) { frame, acc ->
505+
StackTraceFrame(acc, frame)
506+
}, ARTIFICIAL_FRAME
507+
)
507508

508509
private fun <T> createOwner(completion: Continuation<T>, frame: StackTraceFrame?): Continuation<T> {
509510
if (!isInstalled) return completion
510511
val info = DebugCoroutineInfoImpl(completion.context, frame, sequenceNumber.incrementAndGet())
511-
val owner = CoroutineOwner(completion, info, frame)
512+
val owner = CoroutineOwner(completion, info)
512513
capturedCoroutinesMap[owner] = true
513514
if (!isInstalled) capturedCoroutinesMap.clear()
514515
return owner
@@ -531,9 +532,9 @@ internal object DebugProbesImpl {
531532
*/
532533
private class CoroutineOwner<T>(
533534
@JvmField val delegate: Continuation<T>,
534-
@JvmField val info: DebugCoroutineInfoImpl,
535-
private val frame: CoroutineStackFrame?
535+
@JvmField val info: DebugCoroutineInfoImpl
536536
) : Continuation<T> by delegate, CoroutineStackFrame {
537+
private val frame get() = info.creationStackBottom
537538

538539
override val callerFrame: CoroutineStackFrame?
539540
get() = frame?.callerFrame
@@ -551,12 +552,10 @@ internal object DebugProbesImpl {
551552
private fun <T : Throwable> sanitizeStackTrace(throwable: T): List<StackTraceElement> {
552553
val stackTrace = throwable.stackTrace
553554
val size = stackTrace.size
554-
val probeIndex = stackTrace.indexOfLast { it.className == "kotlin.coroutines.jvm.internal.DebugProbesKt" }
555+
val traceStart = 1 + stackTrace.indexOfLast { it.className == "kotlin.coroutines.jvm.internal.DebugProbesKt" }
555556

556557
if (!sanitizeStackTraces) {
557-
return List(size - probeIndex) {
558-
if (it == 0) createArtificialFrame(ARTIFICIAL_FRAME_MESSAGE) else stackTrace[it + probeIndex]
559-
}
558+
return List(size - traceStart) { stackTrace[it + traceStart] }
560559
}
561560

562561
/*
@@ -567,9 +566,8 @@ internal object DebugProbesImpl {
567566
* If an interval of internal methods ends in a synthetic method, the outermost non-synthetic method in that
568567
* interval will also be included.
569568
*/
570-
val result = ArrayList<StackTraceElement>(size - probeIndex + 1)
571-
result += createArtificialFrame(ARTIFICIAL_FRAME_MESSAGE)
572-
var i = probeIndex + 1
569+
val result = ArrayList<StackTraceElement>(size - traceStart + 1)
570+
var i = traceStart
573571
while (i < size) {
574572
if (stackTrace[i].isInternalMethod) {
575573
result += stackTrace[i] // we include the boundary of the span in any case

kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt

+8-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
package kotlinx.coroutines.internal
88

99
import kotlinx.coroutines.*
10+
import _COROUTINE.ARTIFICIAL_FRAME_PACKAGE_NAME
11+
import _COROUTINE.ArtificialStackFrames
1012
import java.util.*
1113
import kotlin.coroutines.*
1214
import kotlin.coroutines.intrinsics.*
@@ -18,6 +20,8 @@ import kotlin.coroutines.intrinsics.*
1820
private const val baseContinuationImplClass = "kotlin.coroutines.jvm.internal.BaseContinuationImpl"
1921
private const val stackTraceRecoveryClass = "kotlinx.coroutines.internal.StackTraceRecoveryKt"
2022

23+
private val ARTIFICIAL_FRAME = ArtificialStackFrames().coroutineBoundary()
24+
2125
private val baseContinuationImplClassName = runCatching {
2226
Class.forName(baseContinuationImplClass).canonicalName
2327
}.getOrElse { baseContinuationImplClass }
@@ -42,7 +46,7 @@ private fun <E : Throwable> E.sanitizeStackTrace(): E {
4246
val adjustment = if (endIndex == -1) 0 else size - endIndex
4347
val trace = Array(size - lastIntrinsic - adjustment) {
4448
if (it == 0) {
45-
artificialFrame("Coroutine boundary")
49+
ARTIFICIAL_FRAME
4650
} else {
4751
stackTrace[startIndex + it - 1]
4852
}
@@ -97,13 +101,13 @@ private fun <E : Throwable> tryCopyAndVerify(exception: E): E? {
97101
* IllegalStateException
98102
* at foo
99103
* at kotlin.coroutines.resumeWith
100-
* (Coroutine boundary)
104+
* at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
101105
* at bar
102106
* ...real stackTrace...
103107
* caused by "IllegalStateException" (original one)
104108
*/
105109
private fun <E : Throwable> createFinalException(cause: E, result: E, resultStackTrace: ArrayDeque<StackTraceElement>): E {
106-
resultStackTrace.addFirst(artificialFrame("Coroutine boundary"))
110+
resultStackTrace.addFirst(ARTIFICIAL_FRAME)
107111
val causeTrace = cause.stackTrace
108112
val size = causeTrace.frameIndex(baseContinuationImplClassName)
109113
if (size == -1) {
@@ -193,12 +197,7 @@ private fun createStackTrace(continuation: CoroutineStackFrame): ArrayDeque<Stac
193197
return stack
194198
}
195199

196-
/**
197-
* @suppress
198-
*/
199-
@InternalCoroutinesApi
200-
public fun artificialFrame(message: String): StackTraceElement = java.lang.StackTraceElement("\b\b\b($message", "\b", "\b", -1)
201-
internal fun StackTraceElement.isArtificial() = className.startsWith("\b\b\b")
200+
internal fun StackTraceElement.isArtificial() = className.startsWith(ARTIFICIAL_FRAME_PACKAGE_NAME)
202201
private fun Array<StackTraceElement>.frameIndex(methodName: String) = indexOfFirst { methodName == it.className }
203202

204203
private fun StackTraceElement.elementWiseEquals(e: StackTraceElement): Boolean {
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
kotlinx.coroutines.RecoverableTestException
22
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:109)
3-
(Coroutine boundary)
3+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
44
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.sendInChannel(StackTraceRecoveryChannelsTest.kt:167)
55
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendWithContext$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:162)
66
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendFromScope$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:172)
77
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:112)
88
Caused by: kotlinx.coroutines.RecoverableTestException
99
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:109)
10-
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
10+
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)

kotlinx-coroutines-core/jvm/test-resources/stacktraces/channels/testOfferWithContextWrapped.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
kotlinx.coroutines.RecoverableTestException
22
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferWithContextWrapped$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:98)
3-
(Coroutine boundary)
3+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
44
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.sendInChannel(StackTraceRecoveryChannelsTest.kt:199)
55
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendWithContext$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:194)
66
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferWithContextWrapped$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:100)

kotlinx-coroutines-core/jvm/test-resources/stacktraces/channels/testOfferWithCurrentContext.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
kotlinx.coroutines.RecoverableTestException
22
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferWithCurrentContext$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:86)
3-
(Coroutine boundary)
3+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
44
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.sendInChannel(StackTraceRecoveryChannelsTest.kt:210)
55
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendWithContext$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:205)
66
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferWithCurrentContext$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:89)
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
kotlinx.coroutines.RecoverableTestException
22
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromChannel$1$job$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:97)
3-
(Coroutine boundary)
3+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
44
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelReceive(StackTraceRecoveryChannelsTest.kt:116)
55
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:101)
66
Caused by: kotlinx.coroutines.RecoverableTestException
77
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromChannel$1$job$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:97)
8-
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
8+
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
kotlinx.coroutines.RecoverableTestException
22
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:110)
3-
(Coroutine boundary)
3+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
44
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelReceive(StackTraceRecoveryChannelsTest.kt:116)
55
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:111)
66
Caused by: kotlinx.coroutines.RecoverableTestException
77
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:110)
8-
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
8+
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
kotlinx.coroutines.RecoverableTestCancellationException
22
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:136)
3-
(Coroutine boundary)
3+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
44
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.sendInChannel(StackTraceRecoveryChannelsTest.kt:167)
55
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendWithContext$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:162)
66
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendFromScope$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:172)
77
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendFromScope$1$deferred$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:126)
88
Caused by: kotlinx.coroutines.RecoverableTestCancellationException
99
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:136)
10-
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
10+
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)

kotlinx-coroutines-core/jvm/test-resources/stacktraces/channels/testSendToChannel.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ java.util.concurrent.CancellationException: RendezvousChannel was cancelled
22
at kotlinx.coroutines.channels.AbstractChannel.cancel(AbstractChannel.kt:630)
33
at kotlinx.coroutines.channels.ReceiveChannel$DefaultImpls.cancel$default(Channel.kt:311)
44
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToChannel$1$job$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:52)
5-
(Coroutine boundary)
5+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
66
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelSend(StackTraceRecoveryChannelsTest.kt:73)
77
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:56)
88
Caused by: java.util.concurrent.CancellationException: RendezvousChannel was cancelled
99
at kotlinx.coroutines.channels.AbstractChannel.cancel(AbstractChannel.kt:630)
1010
at kotlinx.coroutines.channels.ReceiveChannel$DefaultImpls.cancel$default(Channel.kt:311)
1111
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToChannel$1$job$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:52)
12-
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
12+
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
kotlinx.coroutines.RecoverableTestException
22
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:43)
3-
(Coroutine boundary)
3+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
44
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelSend(StackTraceRecoveryChannelsTest.kt:74)
55
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:44)
66
Caused by: kotlinx.coroutines.RecoverableTestException
77
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:43)
8-
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
8+
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
kotlinx.coroutines.RecoverableTestException
22
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest.testResumeModeFastPath(StackTraceRecoveryResumeModeTest.kt:61)
33
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest$testEventLoopDispatcher$1.invokeSuspend(StackTraceRecoveryResumeModeTest.kt:40)
4-
(Coroutine boundary)
4+
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
55
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest$withContext$2.invokeSuspend(StackTraceRecoveryResumeModeTest.kt:76)
66
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest.doFastPath(StackTraceRecoveryResumeModeTest.kt:71)
77
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest.testResumeModeFastPath(StackTraceRecoveryResumeModeTest.kt:62)
88
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest$testEventLoopDispatcher$1.invokeSuspend(StackTraceRecoveryResumeModeTest.kt:40)
99
Caused by: kotlinx.coroutines.RecoverableTestException
1010
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest.testResumeModeFastPath(StackTraceRecoveryResumeModeTest.kt:61)
1111
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest$testEventLoopDispatcher$1.invokeSuspend(StackTraceRecoveryResumeModeTest.kt:40)
12-
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
12+
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)

0 commit comments

Comments
 (0)