(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
|
||||
|
||||
import com.sun.jdi.ObjectReference
|
||||
import com.sun.jdi.ThreadReference
|
||||
import com.sun.jdi.*
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isSubTypeOrSame
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||
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) :
|
||||
BaseMirror<MirrorOfCoroutineOwner>(COROUTINE_OWNER_CLASS_NAME, context) {
|
||||
private val debugCoroutineInfoImpl = DebugCoroutineInfoImpl(context)
|
||||
|
||||
private val infoField = makeField("info")
|
||||
|
||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCoroutineOwner? {
|
||||
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 {
|
||||
@@ -86,6 +90,47 @@ data class MirrorOfCoroutineOwner(val that: ObjectReference, val coroutineInfo:
|
||||
|
||||
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(
|
||||
private val debugProbesImplMirror: DebugProbesImpl,
|
||||
context: DefaultExecutionContext,
|
||||
@@ -156,7 +201,6 @@ class CoroutineInfo private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class MirrorOfCoroutineInfo(
|
||||
val that: ObjectReference,
|
||||
val context: MirrorOfCoroutineContext?,
|
||||
@@ -180,8 +224,10 @@ class CoroutineStackFrame(value: ObjectReference, context: DefaultExecutionConte
|
||||
val callerFrame = if (objectReference is ObjectReference)
|
||||
CoroutineStackFrame(objectReference, context).mirror() else null
|
||||
val stackTraceElementReference = objectValue(value, getStackTraceElementMethod, context)
|
||||
val stackTraceElement =
|
||||
if (stackTraceElementReference is ObjectReference) stackTraceElementMirror.mirror(stackTraceElementReference, context) else null
|
||||
val stackTraceElement = if (stackTraceElementReference is ObjectReference)
|
||||
stackTraceElementMirror.mirror(stackTraceElementReference, context)
|
||||
else
|
||||
null
|
||||
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.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
|
||||
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? =
|
||||
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