mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
IDEA-358435 Counterintuitive behaviour when enabling "Async Stack Traces"
GitOrigin-RevId: b548851ef3a033d1bf85b9bcb1b964c1eb0cbb48
This commit is contained in:
committed by
intellij-monorepo-bot
parent
907e9ffed1
commit
e8108aa2c9
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.idea.debugger.base.util.evaluate.DefaultExecutionCon
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.*
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ContinuationHolder
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.safeSkipCoroutineStackFrameProxy
|
||||
import java.lang.Integer.min
|
||||
|
||||
class CoroutineFrameBuilder {
|
||||
companion object {
|
||||
@@ -133,18 +132,9 @@ class CoroutineFrameBuilder {
|
||||
if (!mode.isCoroutineFound())
|
||||
return null
|
||||
|
||||
val (theFollowingFrames, isFirstSuspendFrame) = theFollowingFrames(frame)
|
||||
if (mode.isSuspendMethodParameter()) {
|
||||
if (theFollowingFrames.isNotEmpty()) {
|
||||
// have to check next frame if that's invokeSuspend:-1 before proceed, otherwise skip
|
||||
// remove negative frames from the stacktrace
|
||||
lookForTheFollowingFrame(theFollowingFrames) ?: return null
|
||||
} else
|
||||
return null
|
||||
}
|
||||
|
||||
val continuation = extractContinuation(frame, mode) ?: return null
|
||||
if (threadAndContextSupportsEvaluation(suspendContext, frame)) {
|
||||
val (theFollowingFrames, isFirstSuspendFrame) = theFollowingFrames(frame)
|
||||
val context = DefaultExecutionContext(suspendContext, frame)
|
||||
val continuationHolder = ContinuationHolder.instance(context)
|
||||
val coroutineInfo = continuationHolder.extractCoroutineInfoData(continuation) ?: return null
|
||||
@@ -160,16 +150,6 @@ class CoroutineFrameBuilder {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun lookForTheFollowingFrame(theFollowingFrames: List<StackFrameProxyImpl>): StackFrameProxyImpl? {
|
||||
for (i in 0 until min(PRE_FETCH_FRAME_COUNT, theFollowingFrames.size)) { // pre-scan PRE_FETCH_FRAME_COUNT frames
|
||||
val nextFrame = theFollowingFrames[i]
|
||||
if (nextFrame.getSuspendExitMode() != SuspendExitMode.NONE) {
|
||||
return nextFrame
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getLVTContinuation(frame: StackFrameProxyImpl?) =
|
||||
frame?.continuationVariableValue()
|
||||
|
||||
@@ -183,7 +163,13 @@ class CoroutineFrameBuilder {
|
||||
val indexOfGetCoroutineSuspended = hasGetCoroutineSuspended(frames)
|
||||
// @TODO if found - skip this thread stack
|
||||
if (indexOfGetCoroutineSuspended < 0 && frames.size > indexOfCurrentFrame + 1) {
|
||||
return Pair(frames.drop(indexOfCurrentFrame + 1), isFirstSuspendFrame(indexOfCurrentFrame, frames))
|
||||
return Pair(
|
||||
frames.asSequence()
|
||||
.drop(indexOfCurrentFrame + 1)
|
||||
.dropWhile { it.getSuspendExitMode() != SuspendExitMode.NONE }
|
||||
.toList(),
|
||||
isFirstSuspendFrame(indexOfCurrentFrame, frames)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
log.error("Frame isn't found on the thread stack.")
|
||||
|
||||
@@ -68,9 +68,6 @@ fun Location.isInvokeSuspend() =
|
||||
fun Location.isInvokeSuspendWithNegativeLineNumber() =
|
||||
isInvokeSuspend() && safeLineNumber() < 0
|
||||
|
||||
fun Location.isFilteredInvokeSuspend() =
|
||||
isInvokeSuspend() || isInvokeSuspendWithNegativeLineNumber()
|
||||
|
||||
fun StackFrameProxyImpl.variableValue(variableName: String): ObjectReference? {
|
||||
val continuationVariable = safeVisibleVariableByName(variableName) ?: return null
|
||||
return getValue(continuationVariable) as? ObjectReference ?: return null
|
||||
@@ -120,7 +117,7 @@ fun Location.sameLineAndMethod(location: Location?): Boolean =
|
||||
location != null && location.safeMethod() == safeMethod() && location.safeLineNumber() == safeLineNumber()
|
||||
|
||||
fun Location.isFilterFromTop(location: Location?): Boolean =
|
||||
isFilteredInvokeSuspend() || sameLineAndMethod(location) || location?.safeMethod() == safeMethod()
|
||||
isInvokeSuspendWithNegativeLineNumber() || sameLineAndMethod(location) || location?.safeMethod() == safeMethod()
|
||||
|
||||
fun Location.isFilterFromBottom(location: Location?): Boolean =
|
||||
sameLineAndMethod(location)
|
||||
|
||||
@@ -35,6 +35,11 @@ public class K2IdeK1CodeContinuationStackTraceTestGenerated extends AbstractK2Id
|
||||
runTest("../testData/continuation/suspendFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendFun1.kt")
|
||||
public void testSuspendFun1() throws Exception {
|
||||
runTest("../testData/continuation/suspendFun1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendFunStackTraceFolded.kt")
|
||||
public void testSuspendFunStackTraceFolded() throws Exception {
|
||||
runTest("../testData/continuation/suspendFunStackTraceFolded.kt");
|
||||
|
||||
@@ -35,6 +35,11 @@ public class K2IdeK2CodeContinuationStackTraceTestGenerated extends AbstractK2Id
|
||||
runTest("../testData/continuation/suspendFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendFun1.kt")
|
||||
public void testSuspendFun1() throws Exception {
|
||||
runTest("../testData/continuation/suspendFun1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendFunStackTraceFolded.kt")
|
||||
public void testSuspendFunStackTraceFolded() throws Exception {
|
||||
runTest("../testData/continuation/suspendFunStackTraceFolded.kt");
|
||||
|
||||
@@ -35,6 +35,11 @@ public class ContinuationStackTraceTestGenerated extends AbstractContinuationSta
|
||||
runTest("testData/continuation/suspendFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendFun1.kt")
|
||||
public void testSuspendFun1() throws Exception {
|
||||
runTest("testData/continuation/suspendFun1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendFunStackTraceFolded.kt")
|
||||
public void testSuspendFunStackTraceFolded() throws Exception {
|
||||
runTest("testData/continuation/suspendFunStackTraceFolded.kt");
|
||||
|
||||
@@ -8,6 +8,8 @@ Thread stack trace:
|
||||
CoroutinePreflightFrame a:!LINE_NUMBER!, SuspendFunKt (coroutine1)
|
||||
($completion, $continuation, $result, a, aParam)
|
||||
CoroutineInfo: -1 coroutine UNKNOWN
|
||||
CoroutineStackFrame test1:!LINE_NUMBER!, SuspendFunKt (coroutine1)
|
||||
(i)
|
||||
KotlinStackFrame invoke:!LINE_NUMBER!, SuspendFunKt$main$result$1 (coroutine1)
|
||||
($completion, p0, this)
|
||||
KotlinStackFrame invoke:!LINE_NUMBER!, SuspendFunKt$main$result$1 (coroutine1)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package continuation
|
||||
// ATTACH_LIBRARY: maven(org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.3.8)-javaagent
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
fun main() {
|
||||
runBlocking {
|
||||
SuspendFun1.f2()
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
object SuspendFun1 {
|
||||
suspend fun f2() {
|
||||
//Breakpoint!
|
||||
yield()
|
||||
println()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
LineBreakpoint created at suspendFun1.kt:16
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
suspendFun1.kt:16
|
||||
Thread stack trace:
|
||||
CoroutinePreflightFrame f2:!LINE_NUMBER!, SuspendFun1 (continuation)
|
||||
($completion, $continuation, $result)
|
||||
CoroutineInfo: 1 coroutine RUNNING
|
||||
CoroutineStackFrame invokeSuspend:!LINE_NUMBER!, SuspendFun1Kt$main$1 (continuation)
|
||||
($completion, $continuation, $result)
|
||||
InlineStackFrame lambda 'with' in 'resumeWith':!LINE_NUMBER!, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
($i$a$-with-BaseContinuationImpl$resumeWith$1, $this$resumeWith_u24lambda_u240, completion, current, param, result, this)
|
||||
KotlinStackFrame resumeWith$$$capture:!LINE_NUMBER!, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
($i$a$-with-BaseContinuationImpl$resumeWith$1, $this$resumeWith_u24lambda_u240, completion, current, param, result, this)
|
||||
KotlinStackFrame FRAME:resumeWith:-1, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
(this)
|
||||
Async stack trace
|
||||
CapturedStackFrame <init>:!LINE_NUMBER!, DebugProbesImpl$CoroutineOwner (kotlinx.coroutines.debug.internal)
|
||||
()
|
||||
CapturedStackFrame createOwner:!LINE_NUMBER!, DebugProbesImpl (kotlinx.coroutines.debug.internal)
|
||||
()
|
||||
CapturedStackFrame probeCoroutineCreated$kotlinx_coroutines_core:!LINE_NUMBER!, DebugProbesImpl (kotlinx.coroutines.debug.internal)
|
||||
()
|
||||
CapturedStackFrame probeCoroutineCreated:!LINE_NUMBER!, DebugProbesKt (kotlin.coroutines.jvm.internal)
|
||||
()
|
||||
CapturedStackFrame createCoroutineUnintercepted:!LINE_NUMBER!, IntrinsicsKt__IntrinsicsJvmKt (kotlin.coroutines.intrinsics)
|
||||
()
|
||||
CapturedStackFrame startCoroutineCancellable:!LINE_NUMBER!, CancellableKt (kotlinx.coroutines.intrinsics)
|
||||
()
|
||||
CapturedStackFrame invoke:!LINE_NUMBER!, CoroutineStart (kotlinx.coroutines)
|
||||
()
|
||||
CapturedStackFrame start:!LINE_NUMBER!, AbstractCoroutine (kotlinx.coroutines)
|
||||
()
|
||||
CapturedStackFrame runBlocking:!LINE_NUMBER!, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
CapturedStackFrame runBlocking:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
CapturedStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
CapturedStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
CapturedStackFrame main:!LINE_NUMBER!, SuspendFun1Kt (continuation)
|
||||
()
|
||||
CapturedStackFrame FRAME:main:-1, SuspendFun1Kt (continuation)
|
||||
()
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
Reference in New Issue
Block a user