Skip to content

Revert displaying fake stack frames as method calls #2695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/images/after.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/before.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 0 additions & 65 deletions kotlinx-coroutines-core/jvm/src/debug/CoroutineDebugging.kt

This file was deleted.

34 changes: 18 additions & 16 deletions kotlinx-coroutines-core/jvm/src/debug/internal/DebugProbesImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package kotlinx.coroutines.debug.internal
import kotlinx.atomicfu.*
import kotlinx.coroutines.*
import kotlinx.coroutines.debug.*
import kotlinx.coroutines.internal.*
import kotlinx.coroutines.internal.ScopeCoroutine
import java.io.*
import java.lang.StackTraceElement
Expand All @@ -17,10 +18,10 @@ import kotlin.concurrent.*
import kotlin.coroutines.*
import kotlin.coroutines.jvm.internal.CoroutineStackFrame
import kotlin.synchronized
import _COROUTINE.ArtificialStackFrames
import kotlinx.coroutines.internal.artificialFrame as createArtificialFrame // IDEA bug workaround

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

private var weakRefCleanerThread: Thread? = null
Expand Down Expand Up @@ -218,7 +219,7 @@ internal object DebugProbesImpl {
info.state
out.print("\n\nCoroutine ${owner.delegate}, state: $state")
if (observedStackTrace.isEmpty()) {
out.print("\n\tat $ARTIFICIAL_FRAME")
out.print("\n\tat ${createArtificialFrame(ARTIFICIAL_FRAME_MESSAGE)}")
printStackTrace(out, info.creationStackTrace)
} else {
printStackTrace(out, enhancedStackTrace)
Expand Down Expand Up @@ -420,17 +421,15 @@ internal object DebugProbesImpl {
return createOwner(completion, frame)
}

private fun List<StackTraceElement>.toStackTraceFrame(): StackTraceFrame =
StackTraceFrame(
foldRight<StackTraceElement, StackTraceFrame?>(null) { frame, acc ->
StackTraceFrame(acc, frame)
}, ARTIFICIAL_FRAME
)
private fun List<StackTraceElement>.toStackTraceFrame(): StackTraceFrame? =
foldRight<StackTraceElement, StackTraceFrame?>(null) { frame, acc ->
StackTraceFrame(acc, frame)
}

private fun <T> createOwner(completion: Continuation<T>, frame: StackTraceFrame?): Continuation<T> {
if (!isInstalled) return completion
val info = DebugCoroutineInfoImpl(completion.context, frame, sequenceNumber.incrementAndGet())
val owner = CoroutineOwner(completion, info)
val owner = CoroutineOwner(completion, info, frame)
capturedCoroutinesMap[owner] = true
if (!isInstalled) capturedCoroutinesMap.clear()
return owner
Expand All @@ -453,9 +452,9 @@ internal object DebugProbesImpl {
*/
private class CoroutineOwner<T>(
@JvmField val delegate: Continuation<T>,
@JvmField val info: DebugCoroutineInfoImpl
@JvmField val info: DebugCoroutineInfoImpl,
private val frame: CoroutineStackFrame?
) : Continuation<T> by delegate, CoroutineStackFrame {
private val frame get() = info.creationStackBottom

override val callerFrame: CoroutineStackFrame?
get() = frame?.callerFrame
Expand All @@ -473,10 +472,12 @@ internal object DebugProbesImpl {
private fun <T : Throwable> sanitizeStackTrace(throwable: T): List<StackTraceElement> {
val stackTrace = throwable.stackTrace
val size = stackTrace.size
val traceStart = 1 + stackTrace.indexOfLast { it.className == "kotlin.coroutines.jvm.internal.DebugProbesKt" }
val probeIndex = stackTrace.indexOfLast { it.className == "kotlin.coroutines.jvm.internal.DebugProbesKt" }

if (!sanitizeStackTraces) {
return List(size - traceStart) { stackTrace[it + traceStart] }
return List(size - probeIndex) {
if (it == 0) createArtificialFrame(ARTIFICIAL_FRAME_MESSAGE) else stackTrace[it + probeIndex]
}
}

/*
Expand All @@ -487,8 +488,9 @@ internal object DebugProbesImpl {
* If an interval of internal methods ends in a synthetic method, the outermost non-synthetic method in that
* interval will also be included.
*/
val result = ArrayList<StackTraceElement>(size - traceStart + 1)
var i = traceStart
val result = ArrayList<StackTraceElement>(size - probeIndex + 1)
result += createArtificialFrame(ARTIFICIAL_FRAME_MESSAGE)
var i = probeIndex + 1
while (i < size) {
if (stackTrace[i].isInternalMethod) {
result += stackTrace[i] // we include the boundary of the span in any case
Expand Down
17 changes: 9 additions & 8 deletions kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
package kotlinx.coroutines.internal

import kotlinx.coroutines.*
import _COROUTINE.ARTIFICIAL_FRAME_PACKAGE_NAME
import _COROUTINE.ArtificialStackFrames
import java.util.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
Expand All @@ -20,8 +18,6 @@ import kotlin.coroutines.intrinsics.*
private const val baseContinuationImplClass = "kotlin.coroutines.jvm.internal.BaseContinuationImpl"
private const val stackTraceRecoveryClass = "kotlinx.coroutines.internal.StackTraceRecoveryKt"

private val ARTIFICIAL_FRAME = ArtificialStackFrames().coroutineBoundary()

private val baseContinuationImplClassName = runCatching {
Class.forName(baseContinuationImplClass).canonicalName
}.getOrElse { baseContinuationImplClass }
Expand All @@ -46,7 +42,7 @@ private fun <E : Throwable> E.sanitizeStackTrace(): E {
val adjustment = if (endIndex == -1) 0 else size - endIndex
val trace = Array(size - lastIntrinsic - adjustment) {
if (it == 0) {
ARTIFICIAL_FRAME
artificialFrame("Coroutine boundary")
} else {
stackTrace[startIndex + it - 1]
}
Expand Down Expand Up @@ -95,13 +91,13 @@ private fun <E : Throwable> recoverFromStackFrame(exception: E, continuation: Co
* IllegalStateException
* at foo
* at kotlin.coroutines.resumeWith
* at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
* (Coroutine boundary)
* at bar
* ...real stackTrace...
* caused by "IllegalStateException" (original one)
*/
private fun <E : Throwable> createFinalException(cause: E, result: E, resultStackTrace: ArrayDeque<StackTraceElement>): E {
resultStackTrace.addFirst(ARTIFICIAL_FRAME)
resultStackTrace.addFirst(artificialFrame("Coroutine boundary"))
val causeTrace = cause.stackTrace
val size = causeTrace.frameIndex(baseContinuationImplClassName)
if (size == -1) {
Expand Down Expand Up @@ -191,7 +187,12 @@ private fun createStackTrace(continuation: CoroutineStackFrame): ArrayDeque<Stac
return stack
}

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

private fun StackTraceElement.elementWiseEquals(e: StackTraceElement): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:109)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.sendInChannel(StackTraceRecoveryChannelsTest.kt:167)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendWithContext$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:162)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendFromScope$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:172)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:112)
Caused by: kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:109)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferWithContextWrapped$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:98)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.sendInChannel(StackTraceRecoveryChannelsTest.kt:199)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendWithContext$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:194)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferWithContextWrapped$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:100)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferWithCurrentContext$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:86)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.sendInChannel(StackTraceRecoveryChannelsTest.kt:210)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendWithContext$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:205)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testOfferWithCurrentContext$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:89)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromChannel$1$job$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:97)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelReceive(StackTraceRecoveryChannelsTest.kt:116)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:101)
Caused by: kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromChannel$1$job$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:97)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:110)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelReceive(StackTraceRecoveryChannelsTest.kt:116)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:111)
Caused by: kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:110)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
kotlinx.coroutines.RecoverableTestCancellationException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:136)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.sendInChannel(StackTraceRecoveryChannelsTest.kt:167)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendWithContext$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:162)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$sendFromScope$2.invokeSuspend(StackTraceRecoveryChannelsTest.kt:172)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendFromScope$1$deferred$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:126)
Caused by: kotlinx.coroutines.RecoverableTestCancellationException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendFromScope$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:136)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ java.util.concurrent.CancellationException: RendezvousChannel was cancelled
at kotlinx.coroutines.channels.AbstractChannel.cancel(AbstractChannel.kt:630)
at kotlinx.coroutines.channels.ReceiveChannel$DefaultImpls.cancel$default(Channel.kt:311)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToChannel$1$job$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:52)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelSend(StackTraceRecoveryChannelsTest.kt:73)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:56)
Caused by: java.util.concurrent.CancellationException: RendezvousChannel was cancelled
at kotlinx.coroutines.channels.AbstractChannel.cancel(AbstractChannel.kt:630)
at kotlinx.coroutines.channels.ReceiveChannel$DefaultImpls.cancel$default(Channel.kt:311)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToChannel$1$job$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:52)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:43)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelSend(StackTraceRecoveryChannelsTest.kt:74)
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:44)
Caused by: kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testSendToClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:43)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest.testResumeModeFastPath(StackTraceRecoveryResumeModeTest.kt:61)
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest$testEventLoopDispatcher$1.invokeSuspend(StackTraceRecoveryResumeModeTest.kt:40)
at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)
(Coroutine boundary)
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest$withContext$2.invokeSuspend(StackTraceRecoveryResumeModeTest.kt:76)
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest.doFastPath(StackTraceRecoveryResumeModeTest.kt:71)
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest.testResumeModeFastPath(StackTraceRecoveryResumeModeTest.kt:62)
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest$testEventLoopDispatcher$1.invokeSuspend(StackTraceRecoveryResumeModeTest.kt:40)
Caused by: kotlinx.coroutines.RecoverableTestException
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest.testResumeModeFastPath(StackTraceRecoveryResumeModeTest.kt:61)
at kotlinx.coroutines.exceptions.StackTraceRecoveryResumeModeTest$testEventLoopDispatcher$1.invokeSuspend(StackTraceRecoveryResumeModeTest.kt:40)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
Loading