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