(CoroutineDebugger) added support for DebugCoroutineInfoImpl in kotlinx-coroutines-core:1.3.8
relates to #KT-40073
This commit is contained in:
+52
-6
@@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror
|
package org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror
|
||||||
|
|
||||||
import com.sun.jdi.ObjectReference
|
import com.sun.jdi.*
|
||||||
import com.sun.jdi.ThreadReference
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isSubTypeOrSame
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isSubTypeOrSame
|
||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||||
@@ -67,11 +66,16 @@ class DebugProbesImpl private constructor(context: DefaultExecutionContext) :
|
|||||||
|
|
||||||
class DebugProbesImplCoroutineOwner(private val coroutineInfo: CoroutineInfo, context: DefaultExecutionContext) :
|
class DebugProbesImplCoroutineOwner(private val coroutineInfo: CoroutineInfo, context: DefaultExecutionContext) :
|
||||||
BaseMirror<MirrorOfCoroutineOwner>(COROUTINE_OWNER_CLASS_NAME, context) {
|
BaseMirror<MirrorOfCoroutineOwner>(COROUTINE_OWNER_CLASS_NAME, context) {
|
||||||
|
private val debugCoroutineInfoImpl = DebugCoroutineInfoImpl(context)
|
||||||
|
|
||||||
private val infoField = makeField("info")
|
private val infoField = makeField("info")
|
||||||
|
|
||||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCoroutineOwner? {
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCoroutineOwner? {
|
||||||
val info = objectValue(value, infoField)
|
val info = objectValue(value, infoField)
|
||||||
return MirrorOfCoroutineOwner(value, coroutineInfo.mirror(info, context))
|
if (debugCoroutineInfoImpl.isCompatible(info)) {
|
||||||
|
return MirrorOfCoroutineOwner(value, debugCoroutineInfoImpl.mirror(info, context))
|
||||||
|
} else
|
||||||
|
return MirrorOfCoroutineOwner(value, coroutineInfo.mirror(info, context))
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -86,6 +90,47 @@ data class MirrorOfCoroutineOwner(val that: ObjectReference, val coroutineInfo:
|
|||||||
|
|
||||||
data class MirrorOfDebugProbesImpl(val that: ObjectReference, val instance: ObjectReference?, val isInstalled: Boolean?)
|
data class MirrorOfDebugProbesImpl(val that: ObjectReference, val instance: ObjectReference?, val isInstalled: Boolean?)
|
||||||
|
|
||||||
|
class DebugCoroutineInfoImpl constructor(context: DefaultExecutionContext) :
|
||||||
|
BaseMirror<MirrorOfCoroutineInfo>("kotlinx.coroutines.debug.internal.DebugCoroutineInfoImpl", context) {
|
||||||
|
private val coroutineContextMirror = CoroutineContext(context)
|
||||||
|
private val javaLangMirror = JavaLangMirror(context)
|
||||||
|
private val javaLangListMirror = JavaUtilAbstractCollection(context)
|
||||||
|
private val stackTraceElement = StackTraceElement(context)
|
||||||
|
|
||||||
|
|
||||||
|
val lastObservedThread by FieldDelegate<ThreadReference>("lastObservedThread")
|
||||||
|
val _context by MethodDelegate<ObjectReference>("getContext")
|
||||||
|
val _state by FieldDelegate<ObjectReference>("_state")
|
||||||
|
val _lastObservedFrame by FieldDelegate<ObjectReference>("_lastObservedFrame")
|
||||||
|
val creationStackBottom by FieldDelegate<ObjectReference>("creationStackBottom")
|
||||||
|
val sequenceNumber by FieldDelegate<LongValue>("sequenceNumber")
|
||||||
|
|
||||||
|
val getCreationStackTrace by MethodDelegate<ObjectReference>("getCreationStackTrace")
|
||||||
|
|
||||||
|
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCoroutineInfo? {
|
||||||
|
val state = _state.value(value)?.let {
|
||||||
|
stringValue(it, javaLangMirror.toString, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
val coroutineContext = coroutineContextMirror.mirror(_context.value(value, context), context)
|
||||||
|
val creationStackBottom = creationStackBottom.value(value)?.let { CoroutineStackFrame(it, context).mirror() }
|
||||||
|
val creationStackTraceMirror = javaLangListMirror.mirror(getCreationStackTrace.value(value, context), context)
|
||||||
|
val creationStackTrace = creationStackTraceMirror?.values?.mapNotNull { stackTraceElement.mirror(it, context) }
|
||||||
|
|
||||||
|
return MirrorOfCoroutineInfo(
|
||||||
|
value,
|
||||||
|
coroutineContext,
|
||||||
|
creationStackBottom,
|
||||||
|
sequenceNumber.value(value)?.longValue(),
|
||||||
|
null,
|
||||||
|
creationStackTrace,
|
||||||
|
state,
|
||||||
|
lastObservedThread.value(value),
|
||||||
|
_lastObservedFrame.value(value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CoroutineInfo private constructor(
|
class CoroutineInfo private constructor(
|
||||||
private val debugProbesImplMirror: DebugProbesImpl,
|
private val debugProbesImplMirror: DebugProbesImpl,
|
||||||
context: DefaultExecutionContext,
|
context: DefaultExecutionContext,
|
||||||
@@ -156,7 +201,6 @@ class CoroutineInfo private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data class MirrorOfCoroutineInfo(
|
data class MirrorOfCoroutineInfo(
|
||||||
val that: ObjectReference,
|
val that: ObjectReference,
|
||||||
val context: MirrorOfCoroutineContext?,
|
val context: MirrorOfCoroutineContext?,
|
||||||
@@ -180,8 +224,10 @@ class CoroutineStackFrame(value: ObjectReference, context: DefaultExecutionConte
|
|||||||
val callerFrame = if (objectReference is ObjectReference)
|
val callerFrame = if (objectReference is ObjectReference)
|
||||||
CoroutineStackFrame(objectReference, context).mirror() else null
|
CoroutineStackFrame(objectReference, context).mirror() else null
|
||||||
val stackTraceElementReference = objectValue(value, getStackTraceElementMethod, context)
|
val stackTraceElementReference = objectValue(value, getStackTraceElementMethod, context)
|
||||||
val stackTraceElement =
|
val stackTraceElement = if (stackTraceElementReference is ObjectReference)
|
||||||
if (stackTraceElementReference is ObjectReference) stackTraceElementMirror.mirror(stackTraceElementReference, context) else null
|
stackTraceElementMirror.mirror(stackTraceElementReference, context)
|
||||||
|
else
|
||||||
|
null
|
||||||
return MirrorOfCoroutineStackFrame(value, callerFrame, stackTraceElement)
|
return MirrorOfCoroutineStackFrame(value, callerFrame, stackTraceElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -10,9 +10,11 @@ import org.jetbrains.kotlin.idea.debugger.coroutine.util.isSubTypeOrSame
|
|||||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||||
|
|
||||||
abstract class BaseMirror<T>(val name: String, context: DefaultExecutionContext) {
|
abstract class BaseMirror<T>(val name: String, context: DefaultExecutionContext) : ReferenceTypeProvider {
|
||||||
val log by logger
|
val log by logger
|
||||||
protected val cls = context.findClassSafe(name) ?: throw IllegalStateException("coroutine-debugger: class $name not found.")
|
private val cls = context.findClassSafe(name) ?: throw IllegalStateException("coroutine-debugger: class $name not found.")
|
||||||
|
|
||||||
|
override fun getCls(): ClassType = cls
|
||||||
|
|
||||||
fun makeField(fieldName: String): Field? =
|
fun makeField(fieldName: String): Field? =
|
||||||
cls.fieldByName(fieldName)
|
cls.fieldByName(fieldName)
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.proxy.mirror
|
||||||
|
|
||||||
|
import com.sun.jdi.*
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||||
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
interface ReferenceTypeProvider {
|
||||||
|
fun getCls(): ClassType
|
||||||
|
}
|
||||||
|
|
||||||
|
class MethodDelegate<T>(val name: String) : ReadOnlyProperty<ReferenceTypeProvider, MethodDelegate.MethodEvaluator<T>> {
|
||||||
|
override fun getValue(thisRef: ReferenceTypeProvider, property: KProperty<*>): MethodEvaluator<T> {
|
||||||
|
return MethodEvaluator(thisRef.getCls().methodsByName(name).singleOrNull())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
class MethodEvaluator<T>(val method: Method?) {
|
||||||
|
fun value(value: ObjectReference?, context: DefaultExecutionContext, vararg values: Value): T? {
|
||||||
|
return value?.let {
|
||||||
|
method?.let {
|
||||||
|
context.invokeMethodAsObject(value, method, *values) as T?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FieldDelegate<T>(val name: String) : ReadOnlyProperty<ReferenceTypeProvider, FieldDelegate.FieldEvaluator<T>> {
|
||||||
|
override fun getValue(thisRef: ReferenceTypeProvider, property: KProperty<*>): FieldEvaluator<T> {
|
||||||
|
return FieldEvaluator(thisRef.getCls().fieldByName(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
class FieldEvaluator<T>(val field: Field?) {
|
||||||
|
fun value(value: ObjectReference): T? =
|
||||||
|
field?.let { value.getValue(it) as T? }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user