@@ -33,9 +33,7 @@ internal object DebugProbesImpl {
3333
3434 @Synchronized
3535 public fun install () {
36- if (++ installations > 1 ) {
37- return
38- }
36+ if (++ installations > 1 ) return
3937
4038 ByteBuddyAgent .install()
4139 val cl = Class .forName(" kotlin.coroutines.jvm.internal.DebugProbesKt" )
@@ -50,7 +48,7 @@ internal object DebugProbesImpl {
5048
5149 @Synchronized
5250 public fun uninstall () {
53- if (installations == 0 ) error( " Agent was not installed" )
51+ check(isInstalled) { " Agent was not installed" }
5452 if (-- installations != 0 ) return
5553
5654 capturedCoroutines.clear()
@@ -66,17 +64,13 @@ internal object DebugProbesImpl {
6664
6765 @Synchronized
6866 public fun hierarchyToString (job : Job ): String {
69- if (! isInstalled) {
70- error(" Debug probes are not installed" )
71- }
72-
67+ check(isInstalled) { " Debug probes are not installed" }
7368 val jobToStack = capturedCoroutines
7469 .filterKeys { it.delegate.context[Job ] != null }
7570 .mapKeys { it.key.delegate.context[Job ]!! }
76-
77- val sb = StringBuilder ()
78- job.build(jobToStack, sb, " " )
79- return sb.toString()
71+ return buildString {
72+ job.build(jobToStack, this , " " )
73+ }
8074 }
8175
8276 private fun Job.build (map : Map <Job , CoroutineState >, builder : StringBuilder , indent : String ) {
@@ -94,57 +88,48 @@ internal object DebugProbesImpl {
9488 val contState = state.state
9589 builder.append(" $str , continuation is $contState at line $element \n " )
9690 }
97-
9891 for (child in children) {
9992 child.build(map, builder, indent + " \t " )
10093 }
10194 }
10295
10396 @Synchronized
10497 public fun dumpCoroutinesState (): List <CoroutineState > {
105- if (! isInstalled) {
106- error(" Debug probes are not installed" )
107- }
108-
98+ check(isInstalled) { " Debug probes are not installed" }
10999 return capturedCoroutines.entries.asSequence()
110100 .map { CoroutineState (it.key.delegate, it.value) }
111101 .sortedBy { it.sequenceNumber }
112102 .toList()
113103 }
114104
115105 public fun dumpCoroutines (out : PrintStream ) {
116- if (! isInstalled) {
117- error(" Debug probes are not installed" )
118- }
119-
120- // Avoid inference with other out/err invocations
121- val resultingString = dumpCoroutines()
122- out .println (resultingString)
106+ check(isInstalled) { " Debug probes are not installed" }
107+ // Avoid inference with other out/err invocations by creating a string first
108+ dumpCoroutines().let { out .println (it) }
123109 }
124110
125111 @Synchronized
126- private fun dumpCoroutines (): String {
112+ private fun dumpCoroutines (): String = buildString {
127113 // Synchronization window can be reduce even more, but no need to do it here
128- return buildString {
129- append(" Coroutines dump ${dateFormat.format(System .currentTimeMillis())} " )
130- capturedCoroutines
131- .asSequence()
132- .sortedBy { it.value.sequenceNumber }
133- .forEach { (key, value) ->
134- val state = if (value.state == State .RUNNING )
135- " ${value.state} (Last suspension stacktrace, not an actual stacktrace)"
136- else value.state.toString()
137-
138- append(" \n\n Coroutine $key , state: $state " )
139- val observedStackTrace = value.lastObservedStackTrace()
140- if (observedStackTrace.isEmpty()) {
141- append(" \n\t at ${artificialFrame(ARTIFICIAL_FRAME_MESSAGE )} " )
142- printStackTrace(value.creationStackTrace)
143- } else {
144- printStackTrace(value.lastObservedStackTrace())
145- }
114+ append(" Coroutines dump ${dateFormat.format(System .currentTimeMillis())} " )
115+ capturedCoroutines
116+ .asSequence()
117+ .sortedBy { it.value.sequenceNumber }
118+ .forEach { (key, value) ->
119+ val state = if (value.state == State .RUNNING )
120+ " ${value.state} (Last suspension stacktrace, not an actual stacktrace)"
121+ else
122+ value.state.toString()
123+
124+ append(" \n\n Coroutine $key , state: $state " )
125+ val observedStackTrace = value.lastObservedStackTrace()
126+ if (observedStackTrace.isEmpty()) {
127+ append(" \n\t at ${artificialFrame(ARTIFICIAL_FRAME_MESSAGE )} " )
128+ printStackTrace(value.creationStackTrace)
129+ } else {
130+ printStackTrace(value.lastObservedStackTrace())
146131 }
147- }
132+ }
148133 }
149134
150135 private fun StringBuilder.printStackTrace (frames : List <StackTraceElement >) {
@@ -158,10 +143,7 @@ internal object DebugProbesImpl {
158143 internal fun probeCoroutineSuspended (frame : Continuation <* >) = updateState(frame, State .SUSPENDED )
159144
160145 private fun updateState (frame : Continuation <* >, state : State ) {
161- if (! isInstalled) {
162- return
163- }
164-
146+ if (! isInstalled) return
165147 // Find ArtificialStackFrame of the coroutine
166148 val owner = frame.owner()
167149 updateState(owner, frame, state)
@@ -174,28 +156,23 @@ internal object DebugProbesImpl {
174156 warn(frame, state)
175157 return
176158 }
177-
178159 coroutineState.updateState(state, frame)
179160 }
180161
181- private fun Continuation <* >.owner (): ArtificialStackFrame <* >? = (this as ? CoroutineStackFrame )?.owner()
162+ private fun Continuation <* >.owner (): ArtificialStackFrame <* >? =
163+ (this as ? CoroutineStackFrame )?.owner()
182164
183- private tailrec fun CoroutineStackFrame.owner (): ArtificialStackFrame <* >? = if (this is ArtificialStackFrame <* >) this else callerFrame?.owner()
165+ private tailrec fun CoroutineStackFrame.owner (): ArtificialStackFrame <* >? =
166+ if (this is ArtificialStackFrame <* >) this else callerFrame?.owner()
184167
185168 internal fun <T > probeCoroutineCreated (completion : Continuation <T >): Continuation <T > {
186- if (! isInstalled) {
187- return completion
188- }
189-
169+ if (! isInstalled) return completion
190170 /*
191171 * If completion already has an owner, it means that we are in scoped coroutine (coroutineScope, withContext etc.),
192172 * then piggyback on its already existing owner and do not replace completion
193173 */
194174 val owner = completion.owner()
195- if (owner != null ) {
196- return completion
197- }
198-
175+ if (owner != null ) return completion
199176 /*
200177 * Here we replace completion with a sequence of CoroutineStackFrame objects
201178 * which represents creation stacktrace, thus making stacktrace recovery mechanism
@@ -208,11 +185,10 @@ internal object DebugProbesImpl {
208185 override val callerFrame: CoroutineStackFrame ? = acc
209186 override fun getStackTraceElement (): StackTraceElement = frame
210187 }
211- }!!
212-
213- val result = ArtificialStackFrame (completion, frame)
214- storeFrame(result, completion)
215- return result
188+ }
189+ return ArtificialStackFrame (completion, frame!! ).also {
190+ storeFrame(it, completion)
191+ }
216192 }
217193
218194 @Synchronized
@@ -227,8 +203,8 @@ internal object DebugProbesImpl {
227203
228204 private class ArtificialStackFrame <T >(
229205 @JvmField val delegate : Continuation <T >,
230- frame : CoroutineStackFrame ) : Continuation<T> by delegate, CoroutineStackFrame by frame {
231-
206+ frame : CoroutineStackFrame
207+ ) : Continuation<T> by delegate, CoroutineStackFrame by frame {
232208 override fun resumeWith (result : Result <T >) {
233209 probeCoroutineCompleted(this )
234210 delegate.resumeWith(result)
@@ -240,14 +216,7 @@ internal object DebugProbesImpl {
240216 private fun <T : Throwable > sanitizeStackTrace (throwable : T ): List <StackTraceElement > {
241217 val stackTrace = throwable.stackTrace
242218 val size = stackTrace.size
243-
244- var probeIndex = - 1
245- for (i in 0 until size) {
246- val name = stackTrace[i].className
247- if (" kotlin.coroutines.jvm.internal.DebugProbesKt" == name) {
248- probeIndex = i
249- }
250- }
219+ val probeIndex = stackTrace.indexOfLast { it.className == " kotlin.coroutines.jvm.internal.DebugProbesKt" }
251220
252221 if (! DebugProbes .sanitizeStackTraces) {
253222 return List (size - probeIndex) {
0 commit comments