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 */ coroutineCreationnull34 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) } 66