@@ -65,27 +65,46 @@ private fun <E : Throwable> recoverFromStackFrame(exception: E, continuation: Co
65
65
mergeRecoveredTraces(recoveredStacktrace, stacktrace)
66
66
}
67
67
68
- /*
69
- * Here we partially copy original exception stacktrace to make current one much prettier.
70
- * E.g. for
71
- * ```
72
- * fun foo() = async { error(...) }
73
- * suspend fun bar() = foo().await()
74
- * ```
75
- * we would like to produce following exception:
76
- * IllegalStateException
77
- * at foo
78
- * at kotlinx.coroutines.resumeWith
79
- * (Current coroutine stacktrace)
80
- * at bar
81
- * ...real stacktrace...
82
- * caused by "IllegalStateException" (original one)
83
- */
84
- // TODO optimizable allocations and passes
85
- stacktrace.addFirst(artificialFrame(" Coroutine boundary" ))
86
- val copied = meaningfulActualStackTrace(cause)
87
- newException.stackTrace = (copied + stacktrace).toTypedArray()
88
- return newException
68
+ // Take recovered stacktrace, merge it with existing one if necessary and return
69
+ return createFinalException(cause, newException, stacktrace)
70
+ }
71
+
72
+ /*
73
+ * Here we partially copy original exception stackTrace to make current one much prettier.
74
+ * E.g. for
75
+ * ```
76
+ * fun foo() = async { error(...) }
77
+ * suspend fun bar() = foo().await()
78
+ * ```
79
+ * we would like to produce following exception:
80
+ * IllegalStateException
81
+ * at foo
82
+ * at kotlin.coroutines.resumeWith
83
+ * (Coroutine boundary)
84
+ * at bar
85
+ * ...real stackTrace...
86
+ * caused by "IllegalStateException" (original one)
87
+ */
88
+ private fun <E : Throwable > createFinalException (cause : E , result : E , resultStackTrace : ArrayDeque <StackTraceElement >): E {
89
+ resultStackTrace.addFirst(artificialFrame(" Coroutine boundary" ))
90
+ val causeTrace = cause.stackTrace
91
+ val size = causeTrace.frameIndex(" kotlin.coroutines.jvm.internal.BaseContinuationImpl" )
92
+ if (size == - 1 ) {
93
+ result.stackTrace = resultStackTrace.toTypedArray()
94
+ return result
95
+ }
96
+
97
+ val mergedStackTrace = arrayOfNulls<StackTraceElement >(resultStackTrace.size + size)
98
+ for (i in 0 until size) {
99
+ mergedStackTrace[i] = causeTrace[i]
100
+ }
101
+
102
+ for ((index, element) in resultStackTrace.withIndex()) {
103
+ mergedStackTrace[size + index] = element
104
+ }
105
+
106
+ result.stackTrace = mergedStackTrace
107
+ return result
89
108
}
90
109
91
110
/* *
@@ -117,25 +136,6 @@ private fun mergeRecoveredTraces(recoveredStacktrace: Array<StackTraceElement>,
117
136
}
118
137
}
119
138
120
- /*
121
- * Returns slice of the original stacktrace from the original exception.
122
- * E.g. for
123
- * at kotlinx.coroutines.PlaygroundKt.foo(PlaygroundKt.kt:14)
124
- * at kotlinx.coroutines.PlaygroundKt$foo$1.invokeSuspend(PlaygroundKt.kt)
125
- * at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
126
- * at kotlinx.coroutines.ResumeModeKt.resumeMode(ResumeMode.kt:67)
127
- * at kotlinx.coroutines.DispatchedKt.resume(Dispatched.kt:277)
128
- * at kotlinx.coroutines.DispatchedKt.dispatch(Dispatched.kt:266)
129
- *
130
- * first two elements will be returned.
131
- */
132
- private fun <E : Throwable > meaningfulActualStackTrace (exception : E ): List <StackTraceElement > {
133
- val stackTrace = exception.stackTrace
134
- val index = stackTrace.frameIndex(" kotlin.coroutines.jvm.internal.BaseContinuationImpl" )
135
- if (index == - 1 ) return emptyList()
136
- return stackTrace.slice(0 until index)
137
- }
138
-
139
139
@Suppress(" NOTHING_TO_INLINE" )
140
140
internal actual suspend inline fun recoverAndThrow (exception : Throwable ): Nothing {
141
141
if (recoveryDisabled(exception)) throw exception
0 commit comments