(CoroutineDebugger) 201 compatibility fix
#KT-39143 fixed
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
# Coroutine Debugger support
|
||||
|
||||
## Java thread stack with coroutine information
|
||||
1. Real frames
|
||||
1. Coroutine 'preflight' frame: [SuspendExitMode](src/org/jetbrains/kotlin/idea/debugger/coroutine/data/SuspendExitMode.kt)
|
||||
is `SUSPEND_LAMBDA` or `SUSPEND_METHOD_PARAMETER`. [Location.isPreflight](org/jetbrains/kotlin/idea/debugger/coroutine/util/CoroutineUtils.kt)
|
||||
1. One or more frames (skipped in debugger)
|
||||
1. Coroutine 'starting' frame: [SuspendExitMode](src/org/jetbrains/kotlin/idea/debugger/coroutine/data/SuspendExitMode.kt) `SUSPEND_METHOD` frame
|
||||
1. Restored from coroutine information frames
|
||||
1. Real frames after the 'starting' frame
|
||||
1. Creation frames (only exists if coroutine agent enabled)
|
||||
|
||||
## Debugger interface
|
||||
Debugger works as a combination of PositionManager and AsyncStackTraceProvider.
|
||||
Once the 'preflight' signature frame found PositionManager forms a 'preflight' frame with coroutine information which gets
|
||||
processed with AsyncStackTraceProvider.
|
||||
+6
-12
@@ -9,7 +9,7 @@ import com.intellij.debugger.engine.AsyncStackTraceProvider
|
||||
import com.intellij.debugger.engine.JavaStackFrame
|
||||
import com.intellij.debugger.engine.SuspendContextImpl
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutinePreflightStackFrame
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutinePreflightFrame
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutineStackFrameItem
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.CoroutineFrameBuilder
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.threadAndContextSupportsEvaluation
|
||||
@@ -19,18 +19,19 @@ class CoroutineAsyncStackTraceProvider : AsyncStackTraceProvider {
|
||||
|
||||
override fun getAsyncStackTrace(stackFrame: JavaStackFrame, suspendContext: SuspendContextImpl): List<StackFrameItem>? {
|
||||
val stackFrameList = hopelessAware {
|
||||
if (stackFrame is CoroutinePreflightStackFrame)
|
||||
if (stackFrame is CoroutinePreflightFrame)
|
||||
processPreflight(stackFrame, suspendContext)
|
||||
else
|
||||
null
|
||||
}
|
||||
return if (stackFrameList == null || stackFrameList.isEmpty())
|
||||
null
|
||||
else stackFrameList
|
||||
else
|
||||
stackFrameList
|
||||
}
|
||||
|
||||
private fun processPreflight(
|
||||
preflightFrame: CoroutinePreflightStackFrame,
|
||||
preflightFrame: CoroutinePreflightFrame,
|
||||
suspendContext: SuspendContextImpl
|
||||
): List<CoroutineStackFrameItem>? {
|
||||
val resumeWithFrame = preflightFrame.threadPreCoroutineFrames.firstOrNull()
|
||||
@@ -41,15 +42,8 @@ class CoroutineAsyncStackTraceProvider : AsyncStackTraceProvider {
|
||||
)
|
||||
) {
|
||||
val doubleFrameList = CoroutineFrameBuilder.build(preflightFrame, suspendContext)
|
||||
val resultList = doubleFrameList.stackTrace + doubleFrameList.creationStackTrace
|
||||
return PreflightProvider(preflightFrame, resultList)
|
||||
return doubleFrameList.allFrames()
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class PreflightProvider(private val preflight: CoroutinePreflightStackFrame, stackFrames: List<CoroutineStackFrameItem>) :
|
||||
List<CoroutineStackFrameItem> by stackFrames {
|
||||
fun getPreflight() =
|
||||
preflight
|
||||
}
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.coroutine.data
|
||||
|
||||
import com.intellij.debugger.engine.DebugProcessImpl
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||
import com.intellij.debugger.ui.impl.watch.MethodsTracker
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||
import com.intellij.xdebugger.frame.XNamedValue
|
||||
import com.sun.jdi.Location
|
||||
import org.jetbrains.kotlin.idea.debugger.*
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isInvokeSuspend
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||
|
||||
/**
|
||||
* Creation frame of coroutine either in RUNNING or SUSPENDED state.
|
||||
*/
|
||||
class CreationCoroutineStackFrameItem(
|
||||
val stackTraceElement: StackTraceElement,
|
||||
location: Location,
|
||||
val first: Boolean
|
||||
) : CoroutineStackFrameItem(location, emptyList()) {
|
||||
fun descriptor(frame: StackFrameProxyImpl) =
|
||||
RestoredStackFrameDescriptor(stackTraceElement, frame)
|
||||
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): CapturedStackFrame {
|
||||
return if (first)
|
||||
CreationCoroutineStackFrame(debugProcess, this)
|
||||
else
|
||||
super.createFrame(debugProcess)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restored frame in SUSPENDED coroutine, not attached to any thread.
|
||||
*/
|
||||
class SuspendCoroutineStackFrameItem(
|
||||
val stackTraceElement: StackTraceElement,
|
||||
location: Location,
|
||||
spilledVariables: List<XNamedValue> = emptyList()
|
||||
) : CoroutineStackFrameItem(location, spilledVariables) {
|
||||
|
||||
fun descriptor(frame: StackFrameProxyImpl) =
|
||||
RestoredStackFrameDescriptor(stackTraceElement, frame)
|
||||
}
|
||||
|
||||
/**
|
||||
* Restored frame in RUNNING coroutine, attached to running thread. Frame references a 'preflight' or 'exit' frame.
|
||||
*/
|
||||
class RestoredCoroutineStackFrameItem(
|
||||
val frame: StackFrameProxyImpl,
|
||||
location: Location,
|
||||
spilledVariables: List<XNamedValue>
|
||||
) : CoroutineStackFrameItem(location, spilledVariables) {
|
||||
|
||||
fun descriptor() =
|
||||
StackFrameDescriptorImpl(frame, MethodsTracker())
|
||||
}
|
||||
|
||||
/**
|
||||
* Restored from memory dump
|
||||
*/
|
||||
class DefaultCoroutineStackFrameItem(location: Location, spilledVariables: List<XNamedValue>) :
|
||||
CoroutineStackFrameItem(location, spilledVariables) {
|
||||
|
||||
fun descriptor(frame: StackFrameProxyImpl) =
|
||||
StackFrameDescriptorImpl(frame, MethodsTracker())
|
||||
}
|
||||
|
||||
/**
|
||||
* Original frame appeared before resumeWith call.
|
||||
*
|
||||
* Sequence is the following
|
||||
*
|
||||
* - KotlinStackFrame
|
||||
* - invokeSuspend(KotlinStackFrame) -|
|
||||
* | replaced with CoroutinePreflightStackFrame
|
||||
* - resumeWith(KotlinStackFrame) ----|
|
||||
* - Kotlin/JavaStackFrame -> PreCoroutineStackFrameItem : CoroutinePreflightStackFrame.threadPreCoroutineFrames
|
||||
*
|
||||
*/
|
||||
|
||||
class RunningCoroutineStackFrameItem(
|
||||
val frame: StackFrameProxyImpl,
|
||||
location: Location,
|
||||
spilledVariables: List<XNamedValue> = emptyList()
|
||||
) : CoroutineStackFrameItem(location, spilledVariables) {
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): CapturedStackFrame {
|
||||
val realStackFrame = debugProcess.invokeInManagerThread {
|
||||
debugProcess.positionManager.createStackFrame(frame, debugProcess, location)
|
||||
}
|
||||
return CoroutineStackFrame(debugProcess, this, realStackFrame)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CoroutineStackFrameItem(val location: Location, val spilledVariables: List<XNamedValue>) :
|
||||
StackFrameItem(location, spilledVariables) {
|
||||
val log by logger
|
||||
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): CapturedStackFrame =
|
||||
CoroutineStackFrame(debugProcess, this)
|
||||
|
||||
fun uniqueId(): String {
|
||||
return location.safeSourceName() + ":" + location.safeMethod().toString() + ":" +
|
||||
location.safeLineNumber() + ":" + location.safeKotlinPreferredLineNumber()
|
||||
}
|
||||
|
||||
fun isInvokeSuspend(): Boolean =
|
||||
location.isInvokeSuspend()
|
||||
}
|
||||
|
||||
class RestoredStackFrameDescriptor(val frame: StackTraceElement, proxy: StackFrameProxyImpl) :
|
||||
StackFrameDescriptorImpl(proxy, MethodsTracker())
|
||||
-8
@@ -35,14 +35,6 @@ data class CoroutineInfoData(
|
||||
|
||||
fun topFrameVariables() = topRestoredFrame()?.spilledVariables ?: emptyList()
|
||||
|
||||
fun restoredStackTrace(mode: SuspendExitMode): List<CoroutineStackFrameItem> =
|
||||
if (stackTrace.isNotEmpty() && stackTrace.first().isInvokeSuspend())
|
||||
stackTrace.drop(1)
|
||||
else if (mode == SuspendExitMode.SUSPEND_METHOD_PARAMETER)
|
||||
stackTrace.drop(1)
|
||||
else
|
||||
stackTrace
|
||||
|
||||
companion object {
|
||||
val log by logger
|
||||
const val DEFAULT_COROUTINE_NAME = "coroutine"
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.coroutine.data;
|
||||
|
||||
enum class SuspendExitMode {
|
||||
SUSPEND_LAMBDA, SUSPEND_METHOD_PARAMETER, SUSPEND_METHOD, UNKNOWN, NONE;
|
||||
|
||||
fun isCoroutineFound() =
|
||||
this == SUSPEND_LAMBDA || this == SUSPEND_METHOD_PARAMETER
|
||||
|
||||
fun isSuspendMethodParameter() =
|
||||
this == SUSPEND_METHOD_PARAMETER
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.coroutine.data
|
||||
|
||||
import com.intellij.debugger.engine.JavaStackFrame
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||
import com.intellij.xdebugger.XSourcePosition
|
||||
import com.intellij.xdebugger.frame.XCompositeNode
|
||||
import com.intellij.xdebugger.frame.XNamedValue
|
||||
import com.intellij.xdebugger.frame.XValueChildrenList
|
||||
|
||||
/**
|
||||
* Puts the frameProxy into JavaStackFrame just to instantiate. SyntheticStackFrame provides it's own data for variables view.
|
||||
*/
|
||||
class SyntheticStackFrame(
|
||||
descriptor: StackFrameDescriptorImpl,
|
||||
private val vars: List<XNamedValue>,
|
||||
private val position: XSourcePosition
|
||||
) :
|
||||
JavaStackFrame(descriptor, true) {
|
||||
|
||||
override fun computeChildren(node: XCompositeNode) {
|
||||
val list = XValueChildrenList()
|
||||
vars.forEach { list.add(it) }
|
||||
node.addChildren(list, true)
|
||||
}
|
||||
|
||||
override fun getSourcePosition(): XSourcePosition? {
|
||||
return position
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
|
||||
val frame = other as? JavaStackFrame ?: return false
|
||||
|
||||
return descriptor.frameProxy == frame.descriptor.frameProxy
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return descriptor.frameProxy.hashCode()
|
||||
}
|
||||
}
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.coroutine.data
|
||||
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||
import com.intellij.debugger.ui.impl.watch.MessageDescriptor
|
||||
import com.intellij.debugger.ui.impl.watch.MethodsTracker
|
||||
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||
import com.intellij.debugger.ui.tree.render.DescriptorLabelListener
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.sun.jdi.ObjectReference
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
||||
import javax.swing.Icon
|
||||
|
||||
@Deprecated("moved to XCoroutineView")
|
||||
class CoroutineDescriptorImpl(private val infoData: CoroutineInfoData) : NodeDescriptorImpl() {
|
||||
lateinit var icon: Icon
|
||||
|
||||
override fun getName() = infoData.key.name
|
||||
|
||||
@Throws(EvaluateException::class)
|
||||
override fun calcRepresentation(context: EvaluationContextImpl?, labelListener: DescriptorLabelListener): String {
|
||||
val thread = infoData.activeThread
|
||||
val name = thread?.name()?.substringBefore(" @${infoData.key.name}") ?: ""
|
||||
val threadState = if (thread != null) DebuggerUtilsEx.getThreadStatusText(thread.status()) else ""
|
||||
val threadName = if (name.isNotEmpty()) " on thread \"$name\":$threadState" else ""
|
||||
return "${infoData.key.name}: ${infoData.key.state} $threadName"
|
||||
}
|
||||
|
||||
override fun isExpandable() = infoData.key.state != State.CREATED
|
||||
|
||||
private fun calcIcon() = when {
|
||||
infoData.isSuspended() -> AllIcons.Debugger.ThreadSuspended
|
||||
infoData.isCreated() -> AllIcons.Debugger.ThreadStates.Idle
|
||||
else -> AllIcons.Debugger.ThreadRunning
|
||||
}
|
||||
|
||||
override fun setContext(context: EvaluationContextImpl?) {
|
||||
icon = calcIcon()
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("moved to XCoroutineView")
|
||||
class CreationFramesDescriptor(val frames: List<StackTraceElement>) :
|
||||
MessageDescriptor(KotlinDebuggerCoroutinesBundle.message("coroutine.dump.creation.trace"), INFORMATION) {
|
||||
|
||||
override fun isExpandable() = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Descriptor for suspend functions
|
||||
*/
|
||||
@Deprecated("moved to XCoroutineView")
|
||||
class SuspendStackFrameDescriptor(
|
||||
val infoData: CoroutineInfoData,
|
||||
val frame: StackTraceElement,
|
||||
proxy: StackFrameProxyImpl,
|
||||
val continuation: ObjectReference
|
||||
) :
|
||||
CoroutineStackFrameDescriptor(proxy) {
|
||||
override fun calcRepresentation(context: EvaluationContextImpl?, labelListener: DescriptorLabelListener?): String {
|
||||
return with(frame) {
|
||||
val pack = className.substringBeforeLast(".", "")
|
||||
val packDisplay = if (pack.isNotEmpty()) "{$pack}" else ""
|
||||
"$methodName:$lineNumber, ${className.substringAfterLast(".")} $packDisplay"
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName(): String? = frame.methodName
|
||||
}
|
||||
|
||||
/**
|
||||
* For the case when no data inside frame is available
|
||||
*/
|
||||
@Deprecated("moved to XCoroutineView")
|
||||
class CoroutineCreatedStackFrameDescriptor(val frame: StackTraceElement, proxy: StackFrameProxyImpl) :
|
||||
CoroutineStackFrameDescriptor(proxy) {
|
||||
override fun calcRepresentation(context: EvaluationContextImpl?, labelListener: DescriptorLabelListener?): String {
|
||||
return with(frame) {
|
||||
val pack = className.substringBeforeLast(".", "")
|
||||
val packDisplay = if (pack.isNotEmpty()) "{$pack}" else ""
|
||||
"$methodName:$lineNumber, ${className.substringAfterLast(".")} $packDisplay"
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName() = null
|
||||
}
|
||||
|
||||
@Deprecated("moved to XCoroutineView")
|
||||
class AsyncStackFrameDescriptor(val infoData: CoroutineInfoData, val frame: StackFrameItem, proxy: StackFrameProxyImpl) :
|
||||
CoroutineStackFrameDescriptor(proxy) {
|
||||
override fun calcRepresentation(context: EvaluationContextImpl?, labelListener: DescriptorLabelListener?): String {
|
||||
return with(frame) {
|
||||
val pack = path().substringBeforeLast(".", "")
|
||||
val packDisplay = if (pack.isNotEmpty()) "{$pack}" else ""
|
||||
"${method()}:${line()}, ${path().substringAfterLast(".")} $packDisplay"
|
||||
}
|
||||
}
|
||||
|
||||
override fun getName() = frame.method()
|
||||
}
|
||||
|
||||
@Deprecated("moved to XCoroutineView")
|
||||
open class CoroutineStackFrameDescriptor(proxy: StackFrameProxyImpl) : StackFrameDescriptorImpl(proxy, MethodsTracker()) {
|
||||
override fun isExpandable() = false
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.coroutine.data
|
||||
|
||||
import com.intellij.debugger.engine.DebugProcessImpl
|
||||
import com.intellij.debugger.engine.JVMStackFrameInfoProvider
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||
import com.intellij.xdebugger.frame.XCompositeNode
|
||||
import com.intellij.xdebugger.frame.XNamedValue
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.intellij.xdebugger.frame.XValueChildrenList
|
||||
import com.sun.jdi.Location
|
||||
import org.jetbrains.kotlin.idea.debugger.*
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.LocationStackFrameProxyImpl
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.findPosition
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isFilteredInvokeSuspend
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||
import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
|
||||
|
||||
/**
|
||||
* Creation frame of coroutine either in RUNNING or SUSPENDED state.
|
||||
*/
|
||||
class CreationCoroutineStackFrameItem(
|
||||
val stackTraceElement: StackTraceElement,
|
||||
location: Location,
|
||||
val first: Boolean
|
||||
) : CoroutineStackFrameItem(location, emptyList()) {
|
||||
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
|
||||
return debugProcess.invokeInManagerThread {
|
||||
val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
|
||||
val locationFrame = LocationStackFrameProxyImpl(location, frame)
|
||||
val position = location.findPosition(debugProcess.project)
|
||||
CreationCoroutineStackFrame(debugProcess, this, first)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restored frame in SUSPENDED coroutine, not attached to any thread.
|
||||
*/
|
||||
class SuspendCoroutineStackFrameItem(
|
||||
val stackTraceElement: StackTraceElement,
|
||||
location: Location,
|
||||
spilledVariables: List<XNamedValue> = emptyList()
|
||||
) : CoroutineStackFrameItem(location, spilledVariables)
|
||||
|
||||
/**
|
||||
* Restored from memory dump
|
||||
*/
|
||||
class DefaultCoroutineStackFrameItem(location: Location, spilledVariables: List<XNamedValue>) :
|
||||
CoroutineStackFrameItem(location, spilledVariables) {
|
||||
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
|
||||
return debugProcess.invokeInManagerThread {
|
||||
val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
|
||||
val locationStackFrameProxyImpl = LocationStackFrameProxyImpl(location, frame)
|
||||
val position = location.findPosition(debugProcess.project) ?: return@invokeInManagerThread null
|
||||
CoroutineStackFrame(debugProcess, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Original frame appeared before resumeWith call.
|
||||
*
|
||||
* Sequence is the following
|
||||
*
|
||||
* - KotlinStackFrame
|
||||
* - invokeSuspend(KotlinStackFrame) -|
|
||||
* | replaced with CoroutinePreflightStackFrame
|
||||
* - resumeWith(KotlinStackFrame) ----|
|
||||
* - Kotlin/JavaStackFrame -> PreCoroutineStackFrameItem : CoroutinePreflightStackFrame.threadPreCoroutineFrames
|
||||
*
|
||||
*/
|
||||
open class RunningCoroutineStackFrameItem(
|
||||
val frame: StackFrameProxyImpl,
|
||||
spilledVariables: List<XNamedValue> = emptyList()
|
||||
) : CoroutineStackFrameItem(frame.location(), spilledVariables), FrameProvider {
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
|
||||
return debugProcess.invokeInManagerThread {
|
||||
CoroutineStackFrame(debugProcess, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun provideFrame(debugProcess: DebugProcessImpl): XStackFrame? =
|
||||
debugProcess.invokeInManagerThread { KotlinStackFrame(frame) }
|
||||
}
|
||||
|
||||
sealed class CoroutineStackFrameItem(val location: Location, val spilledVariables: List<XNamedValue>) :
|
||||
StackFrameItem(location, spilledVariables) {
|
||||
val log by logger
|
||||
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): CoroutineGeneratedFrame? {
|
||||
return debugProcess.invokeInManagerThread {
|
||||
CoroutineStackFrame(debugProcess, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun uniqueId() =
|
||||
location.safeSourceName() + ":" + location.safeMethod().toString() + ":" +
|
||||
location.safeLineNumber() + ":" + location.safeKotlinPreferredLineNumber()
|
||||
}
|
||||
|
||||
interface FrameProvider {
|
||||
fun provideFrame(debugProcess: DebugProcessImpl): XStackFrame?
|
||||
}
|
||||
|
||||
fun DebugProcessImpl.findFirstFrame(): StackFrameProxyImpl? =
|
||||
suspendManager.pausedContext.thread?.forceFrames()?.firstOrNull()
|
||||
|
||||
/**
|
||||
* Coroutine exit frame represented by a stack frames
|
||||
* invokeSuspend():-1
|
||||
* resumeWith()
|
||||
*
|
||||
*/
|
||||
class CoroutinePreflightFrame(
|
||||
val coroutineInfoData: CoroutineInfoData,
|
||||
private val frame: StackFrameProxyImpl,
|
||||
val threadPreCoroutineFrames: List<StackFrameProxyImpl>,
|
||||
val mode: SuspendExitMode
|
||||
) : KotlinStackFrame(frame), JVMStackFrameInfoProvider {
|
||||
|
||||
override fun superBuildVariables(evaluationContext: EvaluationContextImpl, children: XValueChildrenList) {
|
||||
super.superBuildVariables(evaluationContext, children)
|
||||
val topRestoredFrame = coroutineInfoData.stackTrace.firstOrNull()
|
||||
if (topRestoredFrame != null && topRestoredFrame.location.isFilteredInvokeSuspend()) {
|
||||
val firstFrameVariables: List<XNamedValue> = topRestoredFrame.spilledVariables
|
||||
children.let {
|
||||
val varNames = (0 until children.size()).map { children.getName(it) }.toSet()
|
||||
firstFrameVariables.forEach {
|
||||
if (!varNames.contains(it.name))
|
||||
children.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isInLibraryContent() = false
|
||||
|
||||
override fun isSynthetic() = false
|
||||
}
|
||||
|
||||
class CreationCoroutineStackFrame(debugProcess: DebugProcessImpl, item: CoroutineStackFrameItem, val first: Boolean) : CoroutineStackFrame(debugProcess, item) {
|
||||
override fun getCaptionAboveOf() = KotlinDebuggerCoroutinesBundle.message("coroutine.dump.creation.trace")
|
||||
|
||||
override fun hasSeparatorAbove(): Boolean =
|
||||
first
|
||||
}
|
||||
|
||||
open class CoroutineStackFrame(val debugProcess: DebugProcessImpl, val item: CoroutineStackFrameItem) :
|
||||
StackFrameItem.CapturedStackFrame(debugProcess, item) {
|
||||
|
||||
override fun computeChildren(node: XCompositeNode) {
|
||||
if (item is FrameProvider)
|
||||
item.provideFrame(debugProcess)?.computeChildren(node)
|
||||
else
|
||||
super.computeChildren(node)
|
||||
}
|
||||
|
||||
override fun getCaptionAboveOf() = "CoroutineExit"
|
||||
|
||||
override fun hasSeparatorAbove(): Boolean =
|
||||
false
|
||||
}
|
||||
|
||||
typealias CoroutineGeneratedFrame = StackFrameItem.CapturedStackFrame
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.coroutine.data
|
||||
|
||||
import com.intellij.debugger.engine.DebugProcessImpl
|
||||
import com.intellij.debugger.engine.JavaStackFrame
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||
import com.intellij.debugger.ui.tree.render.DescriptorLabelListener
|
||||
import com.intellij.xdebugger.XSourcePosition
|
||||
import com.intellij.xdebugger.frame.XCompositeNode
|
||||
import com.intellij.xdebugger.frame.XNamedValue
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.intellij.xdebugger.frame.XValueChildrenList
|
||||
import com.intellij.xdebugger.impl.frame.XDebuggerFramesList
|
||||
import com.sun.jdi.Location
|
||||
import org.jetbrains.kotlin.idea.debugger.*
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.LocationStackFrameProxyImpl
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.findPosition
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||
import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
|
||||
|
||||
/**
|
||||
* Creation frame of coroutine either in RUNNING or SUSPENDED state.
|
||||
*/
|
||||
class CreationCoroutineStackFrameItem(
|
||||
val stackTraceElement: StackTraceElement,
|
||||
location: Location,
|
||||
val first: Boolean
|
||||
) : CoroutineStackFrameItem(location, emptyList()) {
|
||||
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): XStackFrame? {
|
||||
return debugProcess.invokeInManagerThread {
|
||||
val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
|
||||
val locationFrame = LocationStackFrameProxyImpl(location, frame)
|
||||
val position = location.findPosition(debugProcess.project)
|
||||
CreationCoroutineStackFrame(locationFrame, position, first)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restored frame in SUSPENDED coroutine, not attached to any thread.
|
||||
*/
|
||||
class SuspendCoroutineStackFrameItem(
|
||||
val stackTraceElement: StackTraceElement,
|
||||
location: Location,
|
||||
spilledVariables: List<XNamedValue> = emptyList()
|
||||
) : CoroutineStackFrameItem(location, spilledVariables)
|
||||
|
||||
|
||||
/**
|
||||
* Restored from memory dump
|
||||
*/
|
||||
class DefaultCoroutineStackFrameItem(location: Location, spilledVariables: List<XNamedValue>) :
|
||||
CoroutineStackFrameItem(location, spilledVariables) {
|
||||
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): XStackFrame? {
|
||||
return debugProcess.invokeInManagerThread {
|
||||
val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
|
||||
val locationStackFrameProxyImpl = LocationStackFrameProxyImpl(location, frame)
|
||||
val position = location.findPosition(debugProcess.project) ?: return@invokeInManagerThread null
|
||||
CoroutineStackFrame(locationStackFrameProxyImpl, position, spilledVariables, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Original frame appeared before resumeWith call.
|
||||
*
|
||||
* Sequence is the following
|
||||
*
|
||||
* - KotlinStackFrame
|
||||
* - invokeSuspend(KotlinStackFrame) -|
|
||||
* | replaced with CoroutinePreflightStackFrame
|
||||
* - resumeWith(KotlinStackFrame) ----|
|
||||
* - Kotlin/JavaStackFrame -> PreCoroutineStackFrameItem : CoroutinePreflightStackFrame.threadPreCoroutineFrames
|
||||
*
|
||||
*/
|
||||
open class RunningCoroutineStackFrameItem(
|
||||
val frame: StackFrameProxyImpl,
|
||||
spilledVariables: List<XNamedValue> = emptyList()
|
||||
) : CoroutineStackFrameItem(frame.location(), spilledVariables) {
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): XStackFrame? {
|
||||
return debugProcess.invokeInManagerThread {
|
||||
val position = frame.location().findPosition(debugProcess.project)
|
||||
CoroutineStackFrame(frame, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CoroutineStackFrameItem(val location: Location, val spilledVariables: List<XNamedValue>) :
|
||||
StackFrameItem(location, spilledVariables) {
|
||||
val log by logger
|
||||
|
||||
override fun createFrame(debugProcess: DebugProcessImpl): XStackFrame? {
|
||||
return debugProcess.invokeInManagerThread {
|
||||
val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
|
||||
val locationFrame = LocationStackFrameProxyImpl(location, frame)
|
||||
val position = location.findPosition(debugProcess.project)
|
||||
CoroutineStackFrame(locationFrame, position)
|
||||
}
|
||||
}
|
||||
|
||||
fun uniqueId() =
|
||||
location.safeSourceName() + ":" + location.safeMethod().toString() + ":" +
|
||||
location.safeLineNumber() + ":" + location.safeKotlinPreferredLineNumber()
|
||||
}
|
||||
|
||||
fun DebugProcessImpl.findFirstFrame(): StackFrameProxyImpl? =
|
||||
suspendManager.pausedContext.thread?.forceFrames()?.firstOrNull()
|
||||
|
||||
/**
|
||||
* Coroutine exit frame represented by a stack frames
|
||||
* invokeSuspend():-1
|
||||
* resumeWith()
|
||||
*
|
||||
*/
|
||||
class CoroutinePreflightFrame(
|
||||
val coroutineInfoData: CoroutineInfoData,
|
||||
val frame: StackFrameProxyImpl,
|
||||
val threadPreCoroutineFrames: List<StackFrameProxyImpl>,
|
||||
val mode: SuspendExitMode,
|
||||
private val firstFrameVariables: List<XNamedValue> = coroutineInfoData.topFrameVariables()
|
||||
) : CoroutineStackFrame(frame, null, firstFrameVariables) {
|
||||
|
||||
override fun isInLibraryContent() = false
|
||||
|
||||
override fun isSynthetic() = false
|
||||
|
||||
}
|
||||
|
||||
class CreationCoroutineStackFrame(
|
||||
frame: StackFrameProxyImpl,
|
||||
sourcePosition: XSourcePosition?,
|
||||
val first: Boolean
|
||||
) : CoroutineStackFrame(frame, sourcePosition, emptyList(), false), XDebuggerFramesList.ItemWithSeparatorAbove {
|
||||
|
||||
override fun getCaptionAboveOf() =
|
||||
KotlinDebuggerCoroutinesBundle.message("coroutine.dump.creation.trace")
|
||||
|
||||
override fun hasSeparatorAbove() =
|
||||
first
|
||||
}
|
||||
|
||||
open class CoroutineStackFrame(
|
||||
frame: StackFrameProxyImpl,
|
||||
val position: XSourcePosition?,
|
||||
private val spilledVariables: List<XNamedValue>? = null,
|
||||
private val includeFrameVariables: Boolean = true,
|
||||
) : KotlinStackFrame(frame) {
|
||||
|
||||
init {
|
||||
descriptor.updateRepresentation(null, DescriptorLabelListener.DUMMY_LISTENER)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
|
||||
val frame = other as? JavaStackFrame ?: return false
|
||||
|
||||
return descriptor.frameProxy == frame.descriptor.frameProxy
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return descriptor.frameProxy.hashCode()
|
||||
}
|
||||
|
||||
override fun computeChildren(node: XCompositeNode) {
|
||||
if (includeFrameVariables || spilledVariables == null) {
|
||||
super.computeChildren(node)
|
||||
} else {
|
||||
// ignore original frame variables
|
||||
val list = XValueChildrenList()
|
||||
spilledVariables.forEach { list.add(it) }
|
||||
node.addChildren(list, true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun superBuildVariables(evaluationContext: EvaluationContextImpl, children: XValueChildrenList) {
|
||||
super.superBuildVariables(evaluationContext, children)
|
||||
if (spilledVariables != null) {
|
||||
children.let {
|
||||
val varNames = (0 until children.size()).map { children.getName(it) }.toSet()
|
||||
spilledVariables.forEach {
|
||||
if (!varNames.contains(it.name))
|
||||
children.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSourcePosition() =
|
||||
position ?: super.getSourcePosition()
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.idea.debugger.coroutine.data
|
||||
|
||||
import com.intellij.debugger.engine.DebugProcessImpl
|
||||
import com.intellij.debugger.engine.JVMStackFrameInfoProvider
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||
import com.intellij.xdebugger.frame.XCompositeNode
|
||||
import com.intellij.xdebugger.frame.XNamedValue
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.intellij.xdebugger.frame.XValueChildrenList
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.KotlinDebuggerCoroutinesBundle
|
||||
import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
|
||||
|
||||
|
||||
/**
|
||||
* Coroutine exit frame represented by a stack frames
|
||||
* invokeSuspend():-1
|
||||
* resumeWith()
|
||||
*
|
||||
*/
|
||||
|
||||
class CoroutinePreflightStackFrame(
|
||||
val coroutineInfoData: CoroutineInfoData,
|
||||
private val stackFrameDescriptorImpl: StackFrameDescriptorImpl,
|
||||
val threadPreCoroutineFrames: List<StackFrameProxyImpl>,
|
||||
val mode: SuspendExitMode,
|
||||
private val firstFrameVariables: List<XNamedValue> = coroutineInfoData.topFrameVariables()
|
||||
) : KotlinStackFrame(stackFrameDescriptorImpl), JVMStackFrameInfoProvider {
|
||||
|
||||
override fun superBuildVariables(evaluationContext: EvaluationContextImpl, children: XValueChildrenList) {
|
||||
super.superBuildVariables(evaluationContext, children)
|
||||
children.let {
|
||||
val varNames = (0 until children.size()).map { children.getName(it) }.toSet()
|
||||
firstFrameVariables.forEach {
|
||||
if (!varNames.contains(it.name))
|
||||
children.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isInLibraryContent() = false
|
||||
|
||||
override fun isSynthetic() = false
|
||||
|
||||
fun restoredStackTrace() =
|
||||
coroutineInfoData.restoredStackTrace(mode)
|
||||
}
|
||||
|
||||
enum class SuspendExitMode {
|
||||
SUSPEND_LAMBDA, SUSPEND_METHOD_PARAMETER, SUSPEND_METHOD, UNKNOWN, NONE;
|
||||
|
||||
fun isCoroutineFound() =
|
||||
this == SUSPEND_LAMBDA || this == SUSPEND_METHOD_PARAMETER
|
||||
|
||||
fun isSuspendMethodParameter() =
|
||||
this == SUSPEND_METHOD_PARAMETER
|
||||
}
|
||||
|
||||
class CreationCoroutineStackFrame(debugProcess: DebugProcessImpl, item: StackFrameItem) : CoroutineStackFrame(debugProcess, item) {
|
||||
override fun getCaptionAboveOf() = KotlinDebuggerCoroutinesBundle.message("coroutine.dump.creation.trace")
|
||||
|
||||
override fun hasSeparatorAbove(): Boolean =
|
||||
true
|
||||
}
|
||||
|
||||
open class CoroutineStackFrame(debugProcess: DebugProcessImpl, val item: StackFrameItem, private val realStackFrame: XStackFrame? = null) :
|
||||
StackFrameItem.CapturedStackFrame(debugProcess, item) {
|
||||
|
||||
override fun computeChildren(node: XCompositeNode) {
|
||||
if (realStackFrame != null)
|
||||
realStackFrame.computeChildren(node)
|
||||
else
|
||||
super.computeChildren(node)
|
||||
}
|
||||
|
||||
override fun getCaptionAboveOf() = "CoroutineExit"
|
||||
|
||||
override fun hasSeparatorAbove(): Boolean =
|
||||
false
|
||||
}
|
||||
+2
-5
@@ -49,8 +49,5 @@ class ManagerThreadExecutor(val debugProcess: DebugProcessImpl) {
|
||||
}
|
||||
}
|
||||
|
||||
class ApplicationThreadExecutor {
|
||||
fun schedule(f: () -> Unit, component: Component) {
|
||||
return ApplicationManager.getApplication().invokeLater({ f() }, ModalityState.stateForComponent(component))
|
||||
}
|
||||
}
|
||||
fun invokeLater(component: Component, f: () -> Unit) =
|
||||
ApplicationManager.getApplication().invokeLater({ f() }, ModalityState.stateForComponent(component))
|
||||
|
||||
+8
@@ -6,6 +6,14 @@
|
||||
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy
|
||||
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.sun.jdi.Location
|
||||
|
||||
class SkipCoroutineStackFrameProxyImpl(frame: StackFrameProxyImpl) :
|
||||
StackFrameProxyImpl(frame.threadProxy(), frame.stackFrame, frame.indexFromBottom)
|
||||
|
||||
class LocationStackFrameProxyImpl(val location: Location, frame: StackFrameProxyImpl) :
|
||||
StackFrameProxyImpl(frame.threadProxy(), frame.stackFrame, frame.indexFromBottom) {
|
||||
|
||||
override fun location(): Location =
|
||||
location
|
||||
}
|
||||
|
||||
+57
-29
@@ -8,8 +8,7 @@ package org.jetbrains.kotlin.idea.debugger.coroutine.util
|
||||
import com.intellij.debugger.engine.SuspendContextImpl
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
|
||||
import com.intellij.debugger.ui.impl.watch.MethodsTracker
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||
import com.intellij.xdebugger.frame.XNamedValue
|
||||
import com.sun.jdi.ObjectReference
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.*
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ContinuationHolder
|
||||
@@ -23,14 +22,14 @@ class CoroutineFrameBuilder {
|
||||
val log by logger
|
||||
private const val PRE_FETCH_FRAME_COUNT = 5
|
||||
|
||||
fun build(coroutine: CoroutineInfoData, suspendContext: SuspendContextImpl): DoubleFrameList? =
|
||||
fun build(coroutine: CoroutineInfoData, suspendContext: SuspendContextImpl): CoroutineFrameItemLists? =
|
||||
when {
|
||||
coroutine.isRunning() -> buildStackFrameForActive(coroutine, suspendContext)
|
||||
coroutine.isSuspended() -> DoubleFrameList(coroutine.stackTrace, coroutine.creationStackTrace)
|
||||
coroutine.isSuspended() -> CoroutineFrameItemLists(coroutine.stackTrace, coroutine.creationStackTrace)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun buildStackFrameForActive(coroutine: CoroutineInfoData, suspendContext: SuspendContextImpl): DoubleFrameList? {
|
||||
private fun buildStackFrameForActive(coroutine: CoroutineInfoData, suspendContext: SuspendContextImpl): CoroutineFrameItemLists? {
|
||||
val activeThread = coroutine.activeThread ?: return null
|
||||
|
||||
val coroutineStackFrameList = mutableListOf<CoroutineStackFrameItem>()
|
||||
@@ -43,47 +42,77 @@ class CoroutineFrameBuilder {
|
||||
coroutineStackFrameList.add(it)
|
||||
}
|
||||
|
||||
val doubleFrameList = build(preflightStackFrame, suspendContext)
|
||||
coroutineStackFrameList.addAll(doubleFrameList.stackTrace)
|
||||
return DoubleFrameList(coroutineStackFrameList, doubleFrameList.creationStackTrace)
|
||||
val coroutineFrameLists = build(preflightStackFrame, suspendContext)
|
||||
coroutineStackFrameList.addAll(coroutineFrameLists.frames)
|
||||
return CoroutineFrameItemLists(coroutineStackFrameList, coroutineFrameLists.creationFrames)
|
||||
} else {
|
||||
buildRealStackFrameItem(runningStackFrameProxy)?.let {
|
||||
coroutineStackFrameList.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
return DoubleFrameList(coroutineStackFrameList, emptyList())
|
||||
return CoroutineFrameItemLists(coroutineStackFrameList, emptyList())
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by CoroutineAsyncStackTraceProvider to build XFramesView
|
||||
*/
|
||||
fun build(preflightFrame: CoroutinePreflightStackFrame, suspendContext: SuspendContextImpl): DoubleFrameList {
|
||||
fun build(preflightFrame: CoroutinePreflightFrame, suspendContext: SuspendContextImpl): CoroutineFrameItemLists {
|
||||
val stackFrames = mutableListOf<CoroutineStackFrameItem>()
|
||||
|
||||
stackFrames.addAll(preflightFrame.restoredStackTrace())
|
||||
val (restoredStackTrace, variablesRemovedFromBottomRestoredFrame) = restoredStackTrace(
|
||||
preflightFrame
|
||||
)
|
||||
stackFrames.addAll(restoredStackTrace)
|
||||
|
||||
// rest of the stack
|
||||
// @TODO perhaps we need to merge the dropped frame below with the last restored (at least variables).
|
||||
val framesLeft = preflightFrame.threadPreCoroutineFrames.drop(1)
|
||||
// @TODO perhaps we need to merge the dropped variables with the frame below...
|
||||
val framesLeft = preflightFrame.threadPreCoroutineFrames
|
||||
stackFrames.addAll(framesLeft.mapIndexedNotNull { index, stackFrameProxyImpl ->
|
||||
suspendContext.invokeInManagerThread { buildRealStackFrameItem(stackFrameProxyImpl) }
|
||||
})
|
||||
|
||||
return DoubleFrameList(stackFrames, preflightFrame.coroutineInfoData.creationStackTrace)
|
||||
return CoroutineFrameItemLists(stackFrames, preflightFrame.coroutineInfoData.creationStackTrace)
|
||||
}
|
||||
|
||||
data class DoubleFrameList(
|
||||
val stackTrace: List<CoroutineStackFrameItem>,
|
||||
val creationStackTrace: List<CreationCoroutineStackFrameItem>
|
||||
)
|
||||
fun restoredStackTrace(preflightFrame: CoroutinePreflightFrame): Pair<List<CoroutineStackFrameItem>, List<XNamedValue>> {
|
||||
val preflightFrameLocation = preflightFrame.stackFrameProxy.location()
|
||||
val coroutineStackFrame = preflightFrame.coroutineInfoData.stackTrace
|
||||
val preCoroutineTopFrameLocation = preflightFrame.threadPreCoroutineFrames.firstOrNull()?.location()
|
||||
|
||||
val variablesRemovedFromTopRestoredFrame = mutableListOf<XNamedValue>()
|
||||
val stripTopStackTrace = coroutineStackFrame.dropWhile {
|
||||
it.location.isFilterFromTop(preflightFrameLocation).apply {
|
||||
if (this)
|
||||
variablesRemovedFromTopRestoredFrame.addAll(it.spilledVariables)
|
||||
}
|
||||
}
|
||||
// @TODO Need to merge variablesRemovedFromTopRestoredFrame into stripTopStackTrace.firstOrNull().spilledVariables
|
||||
val variablesRemovedFromBottomRestoredFrame = mutableListOf<XNamedValue>()
|
||||
val restoredFrames = when (preCoroutineTopFrameLocation) {
|
||||
null -> stripTopStackTrace
|
||||
else ->
|
||||
stripTopStackTrace.dropLastWhile {
|
||||
it.location.isFilterFromBottom(preCoroutineTopFrameLocation)
|
||||
.apply { variablesRemovedFromBottomRestoredFrame.addAll(it.spilledVariables) }
|
||||
}
|
||||
}
|
||||
return Pair(restoredFrames, variablesRemovedFromBottomRestoredFrame)
|
||||
}
|
||||
|
||||
data class CoroutineFrameItemLists(
|
||||
val frames: List<CoroutineStackFrameItem>,
|
||||
val creationFrames: List<CreationCoroutineStackFrameItem>
|
||||
) {
|
||||
fun allFrames() =
|
||||
frames + creationFrames
|
||||
}
|
||||
|
||||
private fun buildRealStackFrameItem(
|
||||
frame: StackFrameProxyImpl
|
||||
): RunningCoroutineStackFrameItem? {
|
||||
val location = frame.location()
|
||||
val location = frame.location() ?: return null
|
||||
return if (!location.safeCoroutineExitPointLineNumber())
|
||||
RunningCoroutineStackFrameItem(SkipCoroutineStackFrameProxyImpl(frame), location)
|
||||
RunningCoroutineStackFrameItem(SkipCoroutineStackFrameProxyImpl(frame))
|
||||
else
|
||||
null
|
||||
}
|
||||
@@ -94,14 +123,14 @@ class CoroutineFrameBuilder {
|
||||
fun coroutineExitFrame(
|
||||
frame: StackFrameProxyImpl,
|
||||
suspendContext: SuspendContextImpl
|
||||
): CoroutinePreflightStackFrame? {
|
||||
): CoroutinePreflightFrame? {
|
||||
return suspendContext.invokeInManagerThread {
|
||||
val sem = frame.location().isPreFlight()
|
||||
if (sem.isCoroutineFound()) {
|
||||
val preflightStackFrame = if (sem.isCoroutineFound()) {
|
||||
lookupContinuation(suspendContext, frame, sem)
|
||||
} else
|
||||
null
|
||||
|
||||
preflightStackFrame
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +138,7 @@ class CoroutineFrameBuilder {
|
||||
suspendContext: SuspendContextImpl,
|
||||
frame: StackFrameProxyImpl,
|
||||
mode: SuspendExitMode
|
||||
): CoroutinePreflightStackFrame? {
|
||||
): CoroutinePreflightFrame? {
|
||||
if (!mode.isCoroutineFound())
|
||||
return null
|
||||
|
||||
@@ -133,10 +162,9 @@ class CoroutineFrameBuilder {
|
||||
|
||||
val continuationHolder = ContinuationHolder.instance(context)
|
||||
val coroutineInfo = continuationHolder.extractCoroutineInfoData(continuation) ?: return null
|
||||
val descriptor = StackFrameDescriptorImpl(frame, MethodsTracker())
|
||||
return CoroutinePreflightStackFrame(
|
||||
return CoroutinePreflightFrame(
|
||||
coroutineInfo,
|
||||
descriptor,
|
||||
frame,
|
||||
theFollowingFrames,
|
||||
mode
|
||||
)
|
||||
@@ -174,4 +202,4 @@ class CoroutineFrameBuilder {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-1
@@ -19,6 +19,7 @@ import com.intellij.xdebugger.XSourcePosition
|
||||
import com.sun.jdi.*
|
||||
import org.jetbrains.kotlin.idea.debugger.*
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.SuspendExitMode
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.invokeLater
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
|
||||
|
||||
@@ -71,6 +72,12 @@ fun ReferenceType.isSuspendLambda() =
|
||||
fun Location.isInvokeSuspend() =
|
||||
safeMethod()?.isInvokeSuspend() ?: false
|
||||
|
||||
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
|
||||
@@ -104,7 +111,9 @@ fun StackTraceElement.findPosition(project: Project): XSourcePosition? =
|
||||
getPosition(project, className, lineNumber)
|
||||
|
||||
fun Location.findPosition(project: Project) =
|
||||
getPosition(project, declaringType().name(), lineNumber())
|
||||
readAction {
|
||||
getPosition(project, declaringType().name(), lineNumber())
|
||||
}
|
||||
|
||||
private fun getPosition(project: Project, className: String, lineNumber: Int): XSourcePosition? {
|
||||
val psiFacade = JavaPsiFacade.getInstance(project)
|
||||
@@ -137,3 +146,13 @@ fun threadAndContextSupportsEvaluation(suspendContext: SuspendContextImpl, frame
|
||||
suspendContext.invokeInManagerThread {
|
||||
suspendContext.supportsEvaluation() && frameProxy?.threadProxy()?.supportsEvaluation() ?: false
|
||||
} ?: false
|
||||
|
||||
|
||||
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()
|
||||
|
||||
fun Location.isFilterFromBottom(location: Location?): Boolean =
|
||||
sameLineAndMethod(location)
|
||||
-6
@@ -9,13 +9,7 @@ import com.intellij.debugger.engine.JavaStackFrame
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.xdebugger.XDebuggerUtil
|
||||
import com.intellij.xdebugger.XSourcePosition
|
||||
import com.sun.jdi.Location
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ApplicationThreadExecutor
|
||||
import org.jetbrains.kotlin.idea.debugger.safeLineNumber
|
||||
import org.jetbrains.kotlin.idea.debugger.safeLocation
|
||||
import org.jetbrains.kotlin.idea.debugger.safeMethod
|
||||
|
||||
+2
-2
@@ -205,10 +205,10 @@ class XCoroutineView(val project: Project, val session: XDebugSession) :
|
||||
managerThreadExecutor.on(suspendContext).invoke {
|
||||
val children = XValueChildrenList()
|
||||
val doubleFrameList = CoroutineFrameBuilder.build(infoData, suspendContext)
|
||||
doubleFrameList?.stackTrace?.forEach {
|
||||
doubleFrameList?.frames?.forEach {
|
||||
children.add(CoroutineFrameValue(infoData, it))
|
||||
}
|
||||
doubleFrameList?.creationStackTrace?.let {
|
||||
doubleFrameList?.creationFrames?.let {
|
||||
children.add(CreationFramesContainer(infoData, it))
|
||||
}
|
||||
node.addChildren(children, true)
|
||||
|
||||
+29
-81
@@ -16,9 +16,7 @@ import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.*
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.ApplicationThreadExecutor
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.findPosition
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.invokeInManagerThread
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.proxy.invokeLater
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.suspendContextImpl
|
||||
import org.jetbrains.kotlin.idea.debugger.invokeInManagerThread
|
||||
import java.awt.event.KeyAdapter
|
||||
@@ -26,7 +24,6 @@ import java.awt.event.KeyEvent
|
||||
import java.awt.event.MouseEvent
|
||||
|
||||
class XDebuggerTreeSelectedNodeListener(val session: XDebugSession, val tree: XDebuggerTree) {
|
||||
val applicationThreadExecutor = ApplicationThreadExecutor()
|
||||
val javaDebugProcess = session.debugProcess as JavaDebugProcess
|
||||
val debugProcess: DebugProcessImpl = javaDebugProcess.debuggerSession.process
|
||||
|
||||
@@ -54,90 +51,38 @@ class XDebuggerTreeSelectedNodeListener(val session: XDebugSession, val tree: XD
|
||||
val valueContainer = node.valueContainer
|
||||
val suspendContext = session.suspendContextImpl()
|
||||
if (valueContainer is XCoroutineView.CoroutineFrameValue) {
|
||||
when (val stackFrameItem = valueContainer.frameItem) {
|
||||
is RunningCoroutineStackFrameItem -> {
|
||||
val threadProxy = stackFrameItem.frame.threadProxy()
|
||||
val isCurrentContext = suspendContext.thread == threadProxy
|
||||
createStackAndSetFrame(threadProxy, { it.createStackFrame(stackFrameItem.frame) }, isCurrentContext)
|
||||
}
|
||||
is CreationCoroutineStackFrameItem -> {
|
||||
val position = stackFrameItem.stackTraceElement.findPosition(session.project) ?: return false
|
||||
val threadProxy = suspendContext.thread ?: return false
|
||||
createStackAndSetFrame(threadProxy, {
|
||||
val realFrame = threadProxy.forceFrames().first() ?: return@createStackAndSetFrame null
|
||||
SyntheticStackFrame(stackFrameItem.descriptor(realFrame), emptyList(), position)
|
||||
})
|
||||
}
|
||||
is SuspendCoroutineStackFrameItem -> {
|
||||
val threadProxy = suspendContext.thread ?: return false
|
||||
val position = stackFrameItem.location.findPosition(session.project)
|
||||
?: return false
|
||||
val frameItem = valueContainer.frameItem
|
||||
val frame = frameItem.createFrame(debugProcess) ?: return false
|
||||
|
||||
val executionStack =
|
||||
if (frameItem is RunningCoroutineStackFrameItem)
|
||||
createExecutionStack(frameItem.frame.threadProxy(), debugProcess)
|
||||
else
|
||||
suspendContext.thread?.let {
|
||||
createExecutionStack(it, debugProcess)
|
||||
}
|
||||
|
||||
if (executionStack != null)
|
||||
setCurrentStackFrame(executionStack, frame)
|
||||
|
||||
createStackAndSetFrame(threadProxy, {
|
||||
val realFrame = threadProxy.forceFrames().first() ?: return@createStackAndSetFrame null
|
||||
SyntheticStackFrame(stackFrameItem.descriptor(realFrame), stackFrameItem.spilledVariables, position)
|
||||
})
|
||||
}
|
||||
is RestoredCoroutineStackFrameItem -> {
|
||||
val threadProxy = stackFrameItem.frame.threadProxy()
|
||||
val position = stackFrameItem.location.findPosition(session.project)
|
||||
?: return false
|
||||
createStackAndSetFrame(threadProxy, {
|
||||
SyntheticStackFrame(stackFrameItem.descriptor(), stackFrameItem.spilledVariables, position)
|
||||
})
|
||||
}
|
||||
is DefaultCoroutineStackFrameItem, is SuspendCoroutineStackFrameItem -> {
|
||||
val threadProxy = suspendContext.thread ?: return false
|
||||
val position = stackFrameItem.location.findPosition(session.project)
|
||||
?: return false
|
||||
createStackAndSetFrame(threadProxy, {
|
||||
val realFrame = threadProxy.forceFrames().first() ?: return@createStackAndSetFrame null
|
||||
val descriptor = when (stackFrameItem) {
|
||||
is DefaultCoroutineStackFrameItem -> stackFrameItem.descriptor(realFrame)
|
||||
is SuspendCoroutineStackFrameItem -> stackFrameItem.descriptor(realFrame)
|
||||
else -> null
|
||||
} ?: return@createStackAndSetFrame null
|
||||
SyntheticStackFrame(descriptor, stackFrameItem.spilledVariables, position)
|
||||
})
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun createStackAndSetFrame(
|
||||
threadReferenceProxy: ThreadReferenceProxyImpl,
|
||||
stackFrameProvider: (executionStack: JavaExecutionStack) -> XStackFrame?,
|
||||
isCurrentContext: Boolean = false
|
||||
) {
|
||||
val stackFrameStack = debugProcess.invokeInManagerThread {
|
||||
val executionStack = createExecutionStack(threadReferenceProxy, isCurrentContext);
|
||||
val stackFrame = stackFrameProvider.invoke(executionStack) ?: return@invokeInManagerThread null
|
||||
XStackFrameStack(stackFrame, executionStack)
|
||||
} ?: return
|
||||
setCurrentStackFrame(stackFrameStack)
|
||||
}
|
||||
|
||||
fun setCurrentStackFrame(stackFrameStack: XStackFrameStack) {
|
||||
applicationThreadExecutor.schedule(
|
||||
{
|
||||
session.setCurrentStackFrame(stackFrameStack.executionStack, stackFrameStack.stackFrame, false)
|
||||
}, tree
|
||||
)
|
||||
}
|
||||
|
||||
data class XStackFrameStack(val stackFrame: XStackFrame, val executionStack: XExecutionStack)
|
||||
|
||||
private fun createExecutionStack(proxy: ThreadReferenceProxyImpl, isCurrentContext: Boolean = false): JavaExecutionStack {
|
||||
val executionStack = JavaExecutionStack(proxy, debugProcess, isCurrentContext)
|
||||
executionStack.initTopFrame()
|
||||
return executionStack
|
||||
}
|
||||
fun setCurrentStackFrame(executionStack: XExecutionStack, stackFrame: XStackFrame) =
|
||||
invokeLater(tree) {
|
||||
session.setCurrentStackFrame(executionStack, stackFrame, false)
|
||||
}
|
||||
}
|
||||
|
||||
fun createExecutionStack(threadReference: ThreadReferenceProxyImpl, debugProcess: DebugProcessImpl): JavaExecutionStack? =
|
||||
debugProcess.invokeInManagerThread {
|
||||
val executionStack = JavaExecutionStack(threadReference, debugProcess, debugProcess.isSameContext(threadReference))
|
||||
executionStack.initTopFrame()
|
||||
executionStack
|
||||
}
|
||||
|
||||
data class KeyMouseEvent(val keyEvent: KeyEvent?, val mouseEvent: MouseEvent?) {
|
||||
constructor(keyEvent: KeyEvent) : this(keyEvent, null)
|
||||
constructor(mouseEvent: MouseEvent) : this(null, mouseEvent)
|
||||
@@ -145,4 +90,7 @@ data class KeyMouseEvent(val keyEvent: KeyEvent?, val mouseEvent: MouseEvent?) {
|
||||
fun isKeyEvent() = keyEvent != null
|
||||
|
||||
fun isMouseEvent() = mouseEvent != null
|
||||
}
|
||||
}
|
||||
|
||||
fun DebugProcessImpl.isSameContext(threadReference: ThreadReferenceProxyImpl): Boolean =
|
||||
suspendManager.pausedContext.thread == threadReference
|
||||
-6
@@ -5,13 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.test
|
||||
|
||||
import com.intellij.debugger.engine.JavaStackFrame
|
||||
import com.intellij.debugger.engine.SuspendContextImpl
|
||||
import com.intellij.execution.process.ProcessOutputTypes
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.PreflightProvider
|
||||
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
|
||||
import org.jetbrains.kotlin.idea.debugger.test.util.XDebuggerTestUtil
|
||||
|
||||
abstract class AbstractXCoroutinesStackTraceTest : KotlinDescriptorTestCaseWithStackFrames() {
|
||||
override fun doMultiFileTest(files: TestFiles, preferences: DebuggerPreferences) {
|
||||
|
||||
+5
@@ -33,6 +33,11 @@ public class ContinuationStackTraceTestGenerated extends AbstractContinuationSta
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/continuation/suspendFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendFunWithInner.kt")
|
||||
public void testSuspendFunWithInner() throws Exception {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/continuation/suspendFunWithInner.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("suspendLambda.kt")
|
||||
public void testSuspendLambda() throws Exception {
|
||||
runTest("idea/jvm-debugger/jvm-debugger-test/testData/continuation/suspendLambda.kt");
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.test
|
||||
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Suite
|
||||
|
||||
@Suite.SuiteClasses(
|
||||
ContinuationStackTraceTestGenerated::class,
|
||||
XCoroutinesStackTraceTestGenerated::class
|
||||
)
|
||||
@RunWith(Suite::class)
|
||||
class CoroutineDebuggerTestSuite
|
||||
+22
-25
@@ -19,10 +19,11 @@ import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEdito
|
||||
import com.intellij.testFramework.EdtTestUtil
|
||||
import com.intellij.xdebugger.frame.XNamedValue
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.intellij.xdebugger.impl.frame.XDebuggerFramesList
|
||||
import org.jetbrains.idea.maven.aether.ArtifactKind
|
||||
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.CoroutineAsyncStackTraceProvider
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.PreflightProvider
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CoroutinePreflightFrame
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.CreationCoroutineStackFrameItem
|
||||
import org.jetbrains.kotlin.idea.debugger.invokeInSuspendManagerThread
|
||||
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
|
||||
@@ -44,7 +45,7 @@ abstract class KotlinDescriptorTestCaseWithStackFrames() : KotlinDescriptorTestC
|
||||
val classPath = mutableListOf<String>()
|
||||
|
||||
protected fun out(frame: XStackFrame) {
|
||||
out(INDENT_FRAME, XDebuggerTestUtil.getFramePresentation(frame))
|
||||
out(INDENT_FRAME, frame.javaClass.simpleName + " FRAME:" + XDebuggerTestUtil.getFramePresentation(frame))
|
||||
outVariables(frame)
|
||||
}
|
||||
|
||||
@@ -84,32 +85,28 @@ abstract class KotlinDescriptorTestCaseWithStackFrames() : KotlinDescriptorTestC
|
||||
out("Thread stack trace:")
|
||||
val stackFrames: List<XStackFrame> = XDebuggerTestUtil.collectFrames(executionStack)
|
||||
val suspendContextImpl = suspendContext as SuspendContextImpl
|
||||
suspendContextImpl.runActionInSuspendCommand {
|
||||
for (frame in stackFrames) {
|
||||
if (frame is JavaStackFrame) {
|
||||
out(frame)
|
||||
val stackFrames = suspendContext.invokeInSuspendManagerThread(debugProcess) {
|
||||
asyncStackTraceProvider?.getAsyncStackTrace(frame, suspendContextImpl)
|
||||
}
|
||||
if (stackFrames != null) {
|
||||
if (stackFrames is PreflightProvider) {
|
||||
val preflightFrame = stackFrames.getPreflight()
|
||||
out(0, preflightFrame.coroutineInfoData.key.toString())
|
||||
}
|
||||
for (frameItem in stackFrames) {
|
||||
if (frameItem is CreationCoroutineStackFrameItem && frameItem.first)
|
||||
out(0, "Creation stack frame")
|
||||
|
||||
val frame: XStackFrame? = suspendContext.invokeInSuspendManagerThread(debugProcess) {
|
||||
frameItem.createFrame(debugProcess)
|
||||
}
|
||||
frame?.let {
|
||||
out(frame)
|
||||
}
|
||||
for (frame in stackFrames) {
|
||||
if (frame is JavaStackFrame) {
|
||||
out(frame)
|
||||
if (frame is CoroutinePreflightFrame) {
|
||||
val key = frame.coroutineInfoData.key
|
||||
out(0, "CoroutineInfo: ${key.id} ${key.name} ${key.state}")
|
||||
}
|
||||
val stackFrames = suspendContext.invokeInSuspendManagerThread(debugProcess) {
|
||||
asyncStackTraceProvider?.getAsyncStackTrace(frame, suspendContextImpl)
|
||||
}
|
||||
if (stackFrames != null) {
|
||||
for (frameItem in stackFrames) {
|
||||
val frame: XStackFrame? =
|
||||
frameItem.createFrame(debugProcess)
|
||||
if (frame is XDebuggerFramesList.ItemWithSeparatorAbove && frame.hasSeparatorAbove())
|
||||
out(0, frame.captionAboveOf)
|
||||
|
||||
frame?.let {
|
||||
out(frame)
|
||||
}
|
||||
return@runActionInSuspendCommand
|
||||
}
|
||||
return@doWhenXSessionPausedThenResume
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.*
|
||||
import org.jetbrains.kotlin.idea.debugger.KotlinFrameExtraVariablesProvider
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.ContinuationValueDescriptorImpl
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.data.ContinuationVariableValueDescriptorImpl
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory
|
||||
import org.jetbrains.kotlin.idea.debugger.invokeInManagerThread
|
||||
import org.jetbrains.kotlin.idea.debugger.test.KOTLIN_LIBRARY_NAME
|
||||
@@ -275,7 +275,7 @@ private class Printer(private val delegate: FramePrinterDelegate, private val co
|
||||
is ThisDescriptorImpl -> "this"
|
||||
is FieldDescriptor -> "field"
|
||||
is ArrayElementDescriptor -> "element"
|
||||
is ContinuationValueDescriptorImpl -> "cont"
|
||||
is ContinuationVariableValueDescriptorImpl -> "cont"
|
||||
is MessageDescriptor -> ""
|
||||
else -> "unknown"
|
||||
}
|
||||
|
||||
+4
-3
@@ -109,9 +109,10 @@ internal class KotlinOutputChecker(
|
||||
val disconnectedIndex = lines.indexOfFirst { it.startsWith(DISCONNECT_PREFIX) }
|
||||
lines[disconnectedIndex] = DISCONNECT_PREFIX
|
||||
|
||||
return lines.filter {
|
||||
!(it.matches(JDI_BUG_OUTPUT_PATTERN_1) || it.matches(JDI_BUG_OUTPUT_PATTERN_2))
|
||||
}.joinToString("\n")
|
||||
return lines
|
||||
.map { it.replace("FRAME:(.*):\\d+".toRegex(), "$1:!LINE_NUMBER!") }
|
||||
.filter { !(it.matches(JDI_BUG_OUTPUT_PATTERN_1) || it.matches(JDI_BUG_OUTPUT_PATTERN_2)) }
|
||||
.joinToString("\n")
|
||||
}
|
||||
|
||||
private fun buildOutputString(): String {
|
||||
|
||||
@@ -3,22 +3,22 @@ Run Java
|
||||
Connected to the target VM
|
||||
suspendFun.kt:28
|
||||
Thread stack trace:
|
||||
b:28, SuspendFunKt (coroutine1)
|
||||
KotlinStackFrame b:!LINE_NUMBER!, SuspendFunKt (coroutine1)
|
||||
($completion, b, bParam)
|
||||
a:21, SuspendFunKt (coroutine1)
|
||||
CoroutinePreflightFrame a:!LINE_NUMBER!, SuspendFunKt (coroutine1)
|
||||
($completion, $continuation, $result, a, aParam)
|
||||
CoroutineNameIdState(name=coroutine, id=-1, state=UNKNOWN, dispatcher=null)
|
||||
test1:15, SuspendFunKt (coroutine1)
|
||||
(i, test1)
|
||||
invoke:9, SuspendFunKt$main$result$1 (coroutine1)
|
||||
CoroutineInfo: -1 coroutine UNKNOWN
|
||||
CoroutineStackFrame test1:!LINE_NUMBER!, SuspendFunKt (coroutine1)
|
||||
($completion, $continuation, $result, i, test1)
|
||||
CoroutineStackFrame invoke:!LINE_NUMBER!, SuspendFunKt$main$result$1 (coroutine1)
|
||||
(continuation, p1, this)
|
||||
invokeSuspend:121, IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$3 (kotlin.coroutines.intrinsics)
|
||||
CoroutineStackFrame invokeSuspend:!LINE_NUMBER!, IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$3 (kotlin.coroutines.intrinsics)
|
||||
($i$a$-createCoroutineFromSuspendFunction-IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$2, it, result, this)
|
||||
resumeWith:33, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
CoroutineStackFrame resumeWith:!LINE_NUMBER!, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
($i$a$-with-BaseContinuationImpl$resumeWith$1, $this$with, completion, current, param, result, this)
|
||||
startCoroutine:128, ContinuationKt (kotlin.coroutines)
|
||||
CoroutineStackFrame startCoroutine:!LINE_NUMBER!, ContinuationKt (kotlin.coroutines)
|
||||
($this$startCoroutine, completion, receiver)
|
||||
main:9, SuspendFunKt (coroutine1)
|
||||
CoroutineStackFrame main:!LINE_NUMBER!, SuspendFunKt (coroutine1)
|
||||
(cnt)
|
||||
Disconnected from the target VM
|
||||
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package continuation
|
||||
// ATTACH_LIBRARY: maven(org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.3.5)-javaagent
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
|
||||
fun main() {
|
||||
val mainTestVal = ""
|
||||
runBlocking {
|
||||
val rootCoroutineVal = mainTestVal
|
||||
TestSuspendA().a()
|
||||
print("")
|
||||
}
|
||||
}
|
||||
|
||||
class TestSuspendA {
|
||||
val classField = ""
|
||||
suspend fun a() {
|
||||
val methodVal = ""
|
||||
InClassB().b()
|
||||
print("")
|
||||
}
|
||||
|
||||
class InClassB {
|
||||
val inClassBField = ""
|
||||
|
||||
suspend fun b() {
|
||||
val inClassBMethodVal = ""
|
||||
InClassC().c()
|
||||
print("")
|
||||
}
|
||||
|
||||
inner class InClassC {
|
||||
val inClassCField = inClassBField
|
||||
|
||||
suspend fun c() {
|
||||
yield()
|
||||
val inClassCMethodVal = ""
|
||||
//Breakpoint!
|
||||
print("")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
LineBreakpoint created at suspendFunWithInner.kt:40
|
||||
Run Java
|
||||
Connected to the target VM
|
||||
suspendFunWithInner.kt:40
|
||||
Thread stack trace:
|
||||
CoroutinePreflightFrame c:!LINE_NUMBER!, TestSuspendA$InClassB$InClassC (continuation)
|
||||
($completion, $continuation, $result, inClassCMethodVal, this)
|
||||
CoroutineInfo: 1 coroutine RUNNING
|
||||
CoroutineStackFrame b:!LINE_NUMBER!, TestSuspendA$InClassB (continuation)
|
||||
(inClassBMethodVal, this)
|
||||
CoroutineStackFrame a:!LINE_NUMBER!, TestSuspendA (continuation)
|
||||
(methodVal, this)
|
||||
CoroutineStackFrame invokeSuspend:!LINE_NUMBER!, SuspendFunWithInnerKt$main$1 (continuation)
|
||||
($this$runBlocking, rootCoroutineVal)
|
||||
CoroutineStackFrame resumeWith:!LINE_NUMBER!, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
($i$a$-with-BaseContinuationImpl$resumeWith$1, $this$with, completion, current, param, result, this)
|
||||
CoroutineStackFrame run:!LINE_NUMBER!, DispatchedTask (kotlinx.coroutines)
|
||||
($i$a$-withCoroutineContext-DispatchedTask$run$1, $i$f$withCoroutineContext, context, continuation, countOrElement$iv, delegate, exception, fatalException, job, oldValue$iv, state, taskContext, this)
|
||||
CoroutineStackFrame processNextEvent:!LINE_NUMBER!, EventLoopImplBase (kotlinx.coroutines)
|
||||
(delayed, this)
|
||||
CoroutineStackFrame joinBlocking:!LINE_NUMBER!, BlockingCoroutine (kotlinx.coroutines)
|
||||
(this)
|
||||
CoroutineStackFrame runBlocking:!LINE_NUMBER!, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
(block, context, contextInterceptor, coroutine, currentThread, eventLoop, newContext)
|
||||
CoroutineStackFrame runBlocking:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
(block, context)
|
||||
CoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
CoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
CoroutineStackFrame main:!LINE_NUMBER!, SuspendFunWithInnerKt (continuation)
|
||||
(mainTestVal)
|
||||
Coroutine creation stack trace
|
||||
CreationCoroutineStackFrame createCoroutineUnintercepted:!LINE_NUMBER!, IntrinsicsKt__IntrinsicsJvmKt (kotlin.coroutines.intrinsics)
|
||||
()
|
||||
CreationCoroutineStackFrame startCoroutineCancellable:!LINE_NUMBER!, CancellableKt (kotlinx.coroutines.intrinsics)
|
||||
()
|
||||
CreationCoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
CreationCoroutineStackFrame main:!LINE_NUMBER!, SuspendFunWithInnerKt (continuation)
|
||||
()
|
||||
CreationCoroutineStackFrame FRAME:main:-1, SuspendFunWithInnerKt (continuation)
|
||||
()
|
||||
Disconnected from the target VM
|
||||
|
||||
Process finished with exit code 0
|
||||
+10
-10
@@ -3,24 +3,24 @@ Run Java
|
||||
Connected to the target VM
|
||||
suspendLambda.kt:12
|
||||
Thread stack trace:
|
||||
nextSequence:12, SuspendLambdaKt (continuation)
|
||||
KotlinStackFrame nextSequence:!LINE_NUMBER!, SuspendLambdaKt (continuation)
|
||||
(terms, terms1)
|
||||
invokeSuspend:23, SuspendLambdaKt$fibonacci$1 (continuation)
|
||||
CoroutinePreflightFrame invokeSuspend:!LINE_NUMBER!, SuspendLambdaKt$fibonacci$1 (continuation)
|
||||
($result, $this$sequence, step, terms, this)
|
||||
CoroutineNameIdState(name=coroutine, id=-1, state=UNKNOWN, dispatcher=null)
|
||||
resumeWith:33, kotlin.coroutines.jvm.internal.BaseContinuationImpl
|
||||
CoroutineInfo: -1 coroutine UNKNOWN
|
||||
CoroutineStackFrame resumeWith:!LINE_NUMBER!, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
($i$a$-with-BaseContinuationImpl$resumeWith$1, $this$with, completion, current, param, result, this)
|
||||
hasNext:140, kotlin.sequences.SequenceBuilderIterator
|
||||
CoroutineStackFrame hasNext:!LINE_NUMBER!, SequenceBuilderIterator (kotlin.sequences)
|
||||
(step, this)
|
||||
hasNext:406, kotlin.sequences.TakeSequence$iterator$1
|
||||
CoroutineStackFrame hasNext:!LINE_NUMBER!, TakeSequence$iterator$1 (kotlin.sequences)
|
||||
(this)
|
||||
toCollection:722, kotlin.sequences.SequencesKt___SequencesKt
|
||||
CoroutineStackFrame toCollection:!LINE_NUMBER!, SequencesKt___SequencesKt (kotlin.sequences)
|
||||
($this$toCollection, destination)
|
||||
toMutableList:752, kotlin.sequences.SequencesKt___SequencesKt
|
||||
CoroutineStackFrame toMutableList:!LINE_NUMBER!, SequencesKt___SequencesKt (kotlin.sequences)
|
||||
($this$toMutableList)
|
||||
toList:743, kotlin.sequences.SequencesKt___SequencesKt
|
||||
CoroutineStackFrame toList:!LINE_NUMBER!, SequencesKt___SequencesKt (kotlin.sequences)
|
||||
($this$toList)
|
||||
main:5, continuation.SuspendLambdaKt
|
||||
CoroutineStackFrame main:!LINE_NUMBER!, SuspendLambdaKt (continuation)
|
||||
(a)
|
||||
Disconnected from the target VM
|
||||
|
||||
|
||||
+21
-21
@@ -3,43 +3,43 @@ Run Java
|
||||
Connected to the target VM
|
||||
coroutineSuspendFun.kt:29
|
||||
Thread stack trace:
|
||||
c:29, CoroutineSuspendFunKt (continuation)
|
||||
KotlinStackFrame c:!LINE_NUMBER!, CoroutineSuspendFunKt (continuation)
|
||||
($completion, c, paramB)
|
||||
b:23, CoroutineSuspendFunKt (continuation)
|
||||
CoroutinePreflightFrame b:!LINE_NUMBER!, CoroutineSuspendFunKt (continuation)
|
||||
($completion, $continuation, $result, b, paramA)
|
||||
CoroutineNameIdState(name=coroutine, id=1, state=RUNNING, dispatcher=BlockingEventLoop@6f45df59)
|
||||
a:16, CoroutineSuspendFunKt (continuation)
|
||||
CoroutineInfo: 1 coroutine RUNNING
|
||||
CoroutineStackFrame a:!LINE_NUMBER!, CoroutineSuspendFunKt (continuation)
|
||||
(a)
|
||||
invokeSuspend:10, CoroutineSuspendFunKt$main$1 (continuation)
|
||||
CoroutineStackFrame invokeSuspend:!LINE_NUMBER!, CoroutineSuspendFunKt$main$1 (continuation)
|
||||
($this$runBlocking)
|
||||
resumeWith:33, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
CoroutineStackFrame resumeWith:!LINE_NUMBER!, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
($i$a$-with-BaseContinuationImpl$resumeWith$1, $this$with, completion, current, param, result, this)
|
||||
run:56, DispatchedTask (kotlinx.coroutines)
|
||||
CoroutineStackFrame run:!LINE_NUMBER!, DispatchedTask (kotlinx.coroutines)
|
||||
($i$a$-withCoroutineContext-DispatchedTask$run$1, $i$f$withCoroutineContext, context, continuation, countOrElement$iv, delegate, exception, fatalException, job, oldValue$iv, state, taskContext, this)
|
||||
processNextEvent:272, EventLoopImplBase (kotlinx.coroutines)
|
||||
CoroutineStackFrame processNextEvent:!LINE_NUMBER!, EventLoopImplBase (kotlinx.coroutines)
|
||||
(delayed, this)
|
||||
joinBlocking:79, BlockingCoroutine (kotlinx.coroutines)
|
||||
CoroutineStackFrame joinBlocking:!LINE_NUMBER!, BlockingCoroutine (kotlinx.coroutines)
|
||||
(this)
|
||||
runBlocking:54, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
CoroutineStackFrame runBlocking:!LINE_NUMBER!, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
(block, context, contextInterceptor, coroutine, currentThread, eventLoop, newContext)
|
||||
runBlocking:1, BuildersKt (kotlinx.coroutines)
|
||||
CoroutineStackFrame runBlocking:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
(block, context)
|
||||
CoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
runBlocking$default:36, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
CoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
runBlocking$default:1, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
main:9, CoroutineSuspendFunKt (continuation)
|
||||
CoroutineStackFrame main:!LINE_NUMBER!, CoroutineSuspendFunKt (continuation)
|
||||
(main)
|
||||
Creation stack frame
|
||||
createCoroutineUnintercepted:116, IntrinsicsKt__IntrinsicsJvmKt (kotlin.coroutines.intrinsics)
|
||||
Coroutine creation stack trace
|
||||
CreationCoroutineStackFrame createCoroutineUnintercepted:!LINE_NUMBER!, IntrinsicsKt__IntrinsicsJvmKt (kotlin.coroutines.intrinsics)
|
||||
()
|
||||
startCoroutineCancellable:26, CancellableKt (kotlinx.coroutines.intrinsics)
|
||||
CreationCoroutineStackFrame startCoroutineCancellable:!LINE_NUMBER!, CancellableKt (kotlinx.coroutines.intrinsics)
|
||||
()
|
||||
runBlocking$default:1, BuildersKt (kotlinx.coroutines)
|
||||
CreationCoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
main:9, CoroutineSuspendFunKt (continuation)
|
||||
CreationCoroutineStackFrame main:!LINE_NUMBER!, CoroutineSuspendFunKt (continuation)
|
||||
()
|
||||
main:-1, CoroutineSuspendFunKt (continuation)
|
||||
CreationCoroutineStackFrame FRAME:main:-1, CoroutineSuspendFunKt (continuation)
|
||||
()
|
||||
Disconnected from the target VM
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
package continuation
|
||||
// ATTACH_LIBRARY: maven(org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5-SNAPSHOT)-javaagent
|
||||
// ATTACH_LIBRARY: maven(org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6)-javaagent
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
|
||||
+21
-21
@@ -3,43 +3,43 @@ Run Java
|
||||
Connected to the target VM
|
||||
coroutineSuspendFun136.kt:29
|
||||
Thread stack trace:
|
||||
c:29, CoroutineSuspendFun136Kt (continuation)
|
||||
KotlinStackFrame c:!LINE_NUMBER!, CoroutineSuspendFun136Kt (continuation)
|
||||
($completion, c, paramB)
|
||||
b:23, CoroutineSuspendFun136Kt (continuation)
|
||||
CoroutinePreflightFrame b:!LINE_NUMBER!, CoroutineSuspendFun136Kt (continuation)
|
||||
($completion, $continuation, $result, b, paramA)
|
||||
CoroutineNameIdState(name=coroutine, id=1, state=RUNNING, dispatcher=BlockingEventLoop@305fd85d)
|
||||
a:16, CoroutineSuspendFun136Kt (continuation)
|
||||
CoroutineInfo: 1 coroutine RUNNING
|
||||
CoroutineStackFrame a:!LINE_NUMBER!, CoroutineSuspendFun136Kt (continuation)
|
||||
(a)
|
||||
invokeSuspend:10, CoroutineSuspendFun136Kt$main$1 (continuation)
|
||||
CoroutineStackFrame invokeSuspend:!LINE_NUMBER!, CoroutineSuspendFun136Kt$main$1 (continuation)
|
||||
($this$runBlocking)
|
||||
resumeWith:33, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
CoroutineStackFrame resumeWith:!LINE_NUMBER!, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
($i$a$-with-BaseContinuationImpl$resumeWith$1, $this$with, completion, current, param, result, this)
|
||||
run:56, DispatchedTask (kotlinx.coroutines)
|
||||
CoroutineStackFrame run:!LINE_NUMBER!, DispatchedTask (kotlinx.coroutines)
|
||||
($i$a$-withCoroutineContext-DispatchedTask$run$1, $i$f$withCoroutineContext, context, continuation, countOrElement$iv, delegate, exception, fatalException, job, oldValue$iv, state, taskContext, this)
|
||||
processNextEvent:274, EventLoopImplBase (kotlinx.coroutines)
|
||||
CoroutineStackFrame processNextEvent:!LINE_NUMBER!, EventLoopImplBase (kotlinx.coroutines)
|
||||
(delayed, task, this)
|
||||
joinBlocking:79, BlockingCoroutine (kotlinx.coroutines)
|
||||
CoroutineStackFrame joinBlocking:!LINE_NUMBER!, BlockingCoroutine (kotlinx.coroutines)
|
||||
(this)
|
||||
runBlocking:54, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
CoroutineStackFrame runBlocking:!LINE_NUMBER!, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
(block, context, contextInterceptor, coroutine, currentThread, eventLoop, newContext)
|
||||
runBlocking:1, BuildersKt (kotlinx.coroutines)
|
||||
CoroutineStackFrame runBlocking:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
(block, context)
|
||||
CoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
runBlocking$default:36, BuildersKt__BuildersKt (kotlinx.coroutines)
|
||||
CoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
runBlocking$default:1, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
main:9, CoroutineSuspendFun136Kt (continuation)
|
||||
CoroutineStackFrame main:!LINE_NUMBER!, CoroutineSuspendFun136Kt (continuation)
|
||||
(main)
|
||||
Creation stack frame
|
||||
createCoroutineUnintercepted:116, IntrinsicsKt__IntrinsicsJvmKt (kotlin.coroutines.intrinsics)
|
||||
Coroutine creation stack trace
|
||||
CreationCoroutineStackFrame createCoroutineUnintercepted:!LINE_NUMBER!, IntrinsicsKt__IntrinsicsJvmKt (kotlin.coroutines.intrinsics)
|
||||
()
|
||||
startCoroutineCancellable:26, CancellableKt (kotlinx.coroutines.intrinsics)
|
||||
CreationCoroutineStackFrame startCoroutineCancellable:!LINE_NUMBER!, CancellableKt (kotlinx.coroutines.intrinsics)
|
||||
()
|
||||
runBlocking$default:1, BuildersKt (kotlinx.coroutines)
|
||||
CreationCoroutineStackFrame runBlocking$default:!LINE_NUMBER!, BuildersKt (kotlinx.coroutines)
|
||||
()
|
||||
main:9, CoroutineSuspendFun136Kt (continuation)
|
||||
CreationCoroutineStackFrame main:!LINE_NUMBER!, CoroutineSuspendFun136Kt (continuation)
|
||||
()
|
||||
main:-1, CoroutineSuspendFun136Kt (continuation)
|
||||
CreationCoroutineStackFrame FRAME:main:-1, CoroutineSuspendFun136Kt (continuation)
|
||||
()
|
||||
Disconnected from the target VM
|
||||
|
||||
|
||||
@@ -3,22 +3,22 @@ Run Java
|
||||
Connected to the target VM
|
||||
suspendMain.kt:15
|
||||
Thread stack trace:
|
||||
invokeSuspend:15, SuspendMainKt$main$2 (continuation)
|
||||
CoroutinePreflightFrame invokeSuspend:!LINE_NUMBER!, SuspendMainKt$main$2 (continuation)
|
||||
($result, $this$coroutineScope, this)
|
||||
CoroutineNameIdState(name=coroutine, id=-1, state=UNKNOWN, dispatcher=null)
|
||||
startUndispatchedOrReturn:91, UndispatchedKt (kotlinx.coroutines.intrinsics)
|
||||
CoroutineInfo: -1 coroutine UNKNOWN
|
||||
CoroutineStackFrame startUndispatchedOrReturn:!LINE_NUMBER!, UndispatchedKt (kotlinx.coroutines.intrinsics)
|
||||
($i$a$-undispatchedResult-UndispatchedKt$startUndispatchedOrReturn$2, $i$f$undispatchedResult, $this$startUndispatchedOrReturn, $this$undispatchedResult$iv, block, receiver)
|
||||
coroutineScope:177, CoroutineScopeKt (kotlinx.coroutines)
|
||||
CoroutineStackFrame coroutineScope:!LINE_NUMBER!, CoroutineScopeKt (kotlinx.coroutines)
|
||||
($completion, $i$a$-suspendCoroutineUninterceptedOrReturn-CoroutineScopeKt$coroutineScope$2, block, coroutine, uCont)
|
||||
main:9, SuspendMainKt (continuation)
|
||||
CoroutineStackFrame main:!LINE_NUMBER!, SuspendMainKt (continuation)
|
||||
($completion)
|
||||
invokeSuspend:86, IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$1 (kotlin.coroutines.intrinsics)
|
||||
CoroutineStackFrame invokeSuspend:!LINE_NUMBER!, IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$1 (kotlin.coroutines.intrinsics)
|
||||
($i$a$-createCoroutineFromSuspendFunction-IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$1, it, result, this)
|
||||
resumeWith:33, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
CoroutineStackFrame resumeWith:!LINE_NUMBER!, BaseContinuationImpl (kotlin.coroutines.jvm.internal)
|
||||
($i$a$-with-BaseContinuationImpl$resumeWith$1, $this$with, completion, current, param, result, this)
|
||||
startCoroutine:114, ContinuationKt (kotlin.coroutines)
|
||||
CoroutineStackFrame startCoroutine:!LINE_NUMBER!, ContinuationKt (kotlin.coroutines)
|
||||
($this$startCoroutine, completion)
|
||||
runSuspend:19, RunSuspendKt (kotlin.coroutines.jvm.internal)
|
||||
CoroutineStackFrame runSuspend:!LINE_NUMBER!, RunSuspendKt (kotlin.coroutines.jvm.internal)
|
||||
(block, run)
|
||||
Disconnected from the target VM
|
||||
|
||||
|
||||
@@ -67,8 +67,3 @@ org.jetbrains.kotlin.idea.debugger.test.AsyncStackTraceTestGenerated.testAsyncLa
|
||||
org.jetbrains.kotlin.idea.debugger.test.AsyncStackTraceTestGenerated.testAsyncSimple, redesign test AsyncStackTraces,,
|
||||
org.jetbrains.kotlin.idea.debugger.test.KotlinSteppingTestGenerated.StepOver.testStepOverInlinedLambdaStdlib, fails after advancing bootstrap KT-37879,,
|
||||
org.jetbrains.kotlin.incremental.IncrementalJsKlibCompilerRunnerTestGenerated.ClassHierarchyAffected.testMethodRemoved, FO in klib required,,
|
||||
org.jetbrains.kotlin.idea.debugger.test.XCoroutinesStackTraceTestGenerated.testCoroutineSuspendFun136, running test on SNAPSHOT version,,
|
||||
org.jetbrains.kotlin.idea.debugger.test.XCoroutinesStackTraceTestGenerated.testCoroutineSuspendFun, unstable,,
|
||||
org.jetbrains.kotlin.idea.debugger.test.XCoroutinesStackTraceTestGenerated.testSuspendMain, unstable,,
|
||||
org.jetbrains.kotlin.idea.debugger.test.ContinuationStackTraceTestGenerated.testSuspendLambda, unstable,,
|
||||
org.jetbrains.kotlin.idea.debugger.test.ContinuationStackTraceTestGenerated.testSuspendFun, unstable in 201/202,,
|
||||
|
Reference in New Issue
Block a user