mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
(CoroutineDebugger) kotlinx.coroutines.core:1.3.5 support / dynamicProxy(interface) classes
Original commit: be2185ec01c9fd6c250bd5a2452aae9873b5eeca GitOrigin-RevId: 502e69fbe01dd8db411c3a772a1b479fc1d9b49a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8d7be35656
commit
874c72fba0
@@ -17,12 +17,12 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||
class CoroutineLibraryAgent2Proxy(private val executionContext: DefaultExecutionContext) :
|
||||
CoroutineInfoProvider {
|
||||
val log by logger
|
||||
private val debugProbesImpl = DebugProbesImpl(executionContext)
|
||||
private val debugProbesImpl = DebugProbesImpl.instance(executionContext)
|
||||
private val locationCache = LocationCache(executionContext)
|
||||
private val debugMetadata: DebugMetadata? = DebugMetadata.instance(executionContext)
|
||||
|
||||
override fun dumpCoroutinesInfo(): List<CoroutineInfoData> {
|
||||
val result = debugProbesImpl.dumpCoroutinesInfo(executionContext)
|
||||
val result = debugProbesImpl?.dumpCoroutinesInfo(executionContext) ?: emptyList()
|
||||
return result.mapNotNull { mapToCoroutineInfoData(it) }
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class CoroutineLibraryAgent2Proxy(private val executionContext: DefaultExecution
|
||||
|
||||
fun isInstalled(): Boolean {
|
||||
try {
|
||||
return debugProbesImpl.isInstalledValue ?: false
|
||||
return debugProbesImpl?.isInstalledValue ?: false
|
||||
} catch (e: Exception) {
|
||||
log.error("Exception happened while checking agent status.", e)
|
||||
return false
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.coroutine.util.isSubTypeOrSame
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||
|
||||
abstract class BaseDynamicMirror<T>(val value: ObjectReference, val name: String, val context: DefaultExecutionContext) {
|
||||
val log by logger
|
||||
|
||||
val cls: ReferenceType? = value.referenceType()
|
||||
|
||||
fun makeField(fieldName: String): Field? =
|
||||
cls?.let { it.fieldByName(fieldName) }
|
||||
|
||||
fun makeMethod(methodName: String): Method? =
|
||||
cls?.let { it.methodsByName(methodName).single() }
|
||||
|
||||
fun makeMethod(methodName: String, signature: String): Method? =
|
||||
cls?.let { it.methodsByName(methodName, signature).single() }
|
||||
|
||||
fun isCompatible(value: ObjectReference?) =
|
||||
value?.let { it.referenceType().isSubTypeOrSame(name) } ?: false
|
||||
|
||||
fun mirror(): T? {
|
||||
if (!isCompatible(value)) {
|
||||
log.trace("Value ${value.referenceType()} is not compatible with $name.")
|
||||
return null
|
||||
} else
|
||||
return fetchMirror(value, context)
|
||||
}
|
||||
|
||||
fun staticObjectValue(fieldName: String): ObjectReference? {
|
||||
val keyFieldRef = makeField(fieldName)
|
||||
return cls?.let { it.getValue(keyFieldRef) as? ObjectReference }
|
||||
}
|
||||
|
||||
fun staticMethodValue(instance: ObjectReference?, method: Method?, context: DefaultExecutionContext, vararg values: Value?) =
|
||||
instance?.let {
|
||||
method?.let { m ->
|
||||
context.invokeMethod(it, m, values.asList()) as? ObjectReference
|
||||
}
|
||||
}
|
||||
|
||||
fun staticMethodValue(method: Method?, context: DefaultExecutionContext, vararg values: Value?) =
|
||||
cls?.let {
|
||||
method?.let {
|
||||
if (cls is ClassType)
|
||||
context.invokeMethodSafe(cls, method, values.asList()) as? ObjectReference
|
||||
else
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun stringValue(value: ObjectReference, field: Field?) =
|
||||
field?.let {
|
||||
(value.getValue(it) as? StringReference)?.value()
|
||||
}
|
||||
|
||||
fun byteValue(value: ObjectReference, field: Field?) =
|
||||
field?.let {
|
||||
(value.getValue(it) as? ByteValue)?.value()
|
||||
}
|
||||
|
||||
fun threadValue(value: ObjectReference, field: Field?) =
|
||||
field?.let {
|
||||
value.getValue(it) as? ThreadReference
|
||||
}
|
||||
|
||||
fun stringValue(value: ObjectReference, method: Method?, context: DefaultExecutionContext) =
|
||||
method?.let {
|
||||
(context.invokeMethod(value, it, emptyList()) as? StringReference)?.value()
|
||||
}
|
||||
|
||||
fun objectValue(value: ObjectReference?, method: Method?, context: DefaultExecutionContext, vararg values: Value) =
|
||||
value?.let {
|
||||
method?.let {
|
||||
context.invokeMethodAsObject(value, method, *values)
|
||||
}
|
||||
}
|
||||
|
||||
fun longValue(value: ObjectReference, method: Method?, context: DefaultExecutionContext, vararg values: Value) =
|
||||
method?.let { (context.invokeMethod(value, it, values.asList()) as? LongValue)?.longValue() }
|
||||
|
||||
fun intValue(value: ObjectReference, method: Method?, context: DefaultExecutionContext, vararg values: Value) =
|
||||
method?.let { (context.invokeMethod(value, it, values.asList()) as? IntegerValue)?.intValue() }
|
||||
|
||||
fun booleanValue(value: ObjectReference?, method: Method?, context: DefaultExecutionContext, vararg values: Value): Boolean? {
|
||||
value ?: return null
|
||||
method ?: return null
|
||||
return (context.invokeMethod(value, method, values.asList()) as? BooleanValue)?.booleanValue()
|
||||
}
|
||||
|
||||
fun objectValue(value: ObjectReference, field: Field?) =
|
||||
field?.let { value.getValue(it) as ObjectReference? }
|
||||
|
||||
fun intValue(value: ObjectReference, field: Field?) =
|
||||
field?.let { (value.getValue(it) as? IntegerValue)?.intValue() }
|
||||
|
||||
fun longValue(value: ObjectReference, field: Field?) =
|
||||
field?.let { (value.getValue(it) as? LongValue)?.longValue() }
|
||||
|
||||
fun booleanValue(value: ObjectReference?, field: Field?) =
|
||||
field?.let { (value?.getValue(field) as? BooleanValue)?.booleanValue() }
|
||||
|
||||
protected abstract fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): T?
|
||||
}
|
||||
@@ -67,8 +67,8 @@ class CoroutineId(context: DefaultExecutionContext) : ContextKey<Long>("kotlinx.
|
||||
override fun key() = key
|
||||
}
|
||||
|
||||
class Job(context: DefaultExecutionContext) : ContextKey<ObjectReference>("kotlinx.coroutines.Job", context) {
|
||||
val key = staticObjectValue("Key")
|
||||
class Job(context: DefaultExecutionContext) : ContextKey<ObjectReference>("kotlinx.coroutines.Job\$Key", context) {
|
||||
val key = staticObjectValue("\$\$INSTANCE")
|
||||
|
||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): ObjectReference? {
|
||||
return value
|
||||
|
||||
@@ -7,16 +7,18 @@ package org.jetbrains.kotlin.idea.debugger.coroutine.proxy.mirror
|
||||
|
||||
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
|
||||
|
||||
class DebugProbesImpl internal constructor(context: DefaultExecutionContext) :
|
||||
class DebugProbesImpl private constructor(context: DefaultExecutionContext) :
|
||||
BaseMirror<MirrorOfDebugProbesImpl>("kotlinx.coroutines.debug.internal.DebugProbesImpl", context) {
|
||||
val javaLangListMirror = JavaUtilAbstractCollection(context)
|
||||
val stackTraceElement = StackTraceElement(context)
|
||||
val coroutineInfo = CoroutineInfo(this, context)
|
||||
val coroutineInfo = CoroutineInfo.instance(this, context) ?: throw IllegalStateException("CoroutineInfo implementation not found.")
|
||||
val debugProbesCoroutineOwner = DebugProbesImpl_CoroutineOwner(coroutineInfo, context)
|
||||
val instance = staticObjectValue("INSTANCE")
|
||||
val isInstalledMethod = makeMethod("isInstalled\$kotlinx_coroutines_debug", "()Z")
|
||||
?: makeMethod("isInstalled\$kotlinx_coroutines_core", "()Z") ?: throw IllegalStateException("isInstalledMethod not found")
|
||||
val isInstalledValue = booleanValue(instance, isInstalledMethod, context)
|
||||
val enhanceStackTraceWithThreadDumpMethod = makeMethod("enhanceStackTraceWithThreadDump")
|
||||
val dumpMethod = makeMethod("dumpCoroutinesInfo", "()Ljava/util/List;")
|
||||
@@ -49,10 +51,13 @@ class DebugProbesImpl internal constructor(context: DefaultExecutionContext) :
|
||||
}
|
||||
|
||||
companion object {
|
||||
val log by logger
|
||||
|
||||
fun instance(context: DefaultExecutionContext) =
|
||||
try {
|
||||
DebugProbesImpl(context)
|
||||
} catch (e: IllegalStateException) {
|
||||
log.warn("Attempt to access DebugProbesImpl", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -79,12 +84,15 @@ data class MirrorOfCoroutineOwner(val that: ObjectReference, val coroutineInfo:
|
||||
|
||||
data class MirrorOfDebugProbesImpl(val that: ObjectReference, val instance: ObjectReference?, val isInstalled: Boolean?)
|
||||
|
||||
class CoroutineInfo(val debugProbesImplMirror: DebugProbesImpl, context: DefaultExecutionContext) :
|
||||
BaseMirror<MirrorOfCoroutineInfo>("kotlinx.coroutines.debug.CoroutineInfo", context) {
|
||||
class CoroutineInfo private constructor(
|
||||
val debugProbesImplMirror: DebugProbesImpl,
|
||||
context: DefaultExecutionContext,
|
||||
val className: String = AGENT_134_CLASS_NAME
|
||||
) :
|
||||
BaseMirror<MirrorOfCoroutineInfo>(className, context) {
|
||||
val javaLangMirror = JavaLangMirror(context)
|
||||
val javaLangListMirror = JavaUtilAbstractCollection(context)
|
||||
private val coroutineContextMirror = CoroutineContext(context)
|
||||
private val coroutineStackFrameMirror = CoroutineStackFrame(context)
|
||||
private val stackTraceElement = StackTraceElement(context)
|
||||
private val contextFieldRef = makeField("context")
|
||||
private val creationStackBottom = makeField("creationStackBottom")
|
||||
@@ -96,13 +104,30 @@ class CoroutineInfo(val debugProbesImplMirror: DebugProbesImpl, context: Default
|
||||
private val lastObservedFrameField = makeField("lastObservedFrame")
|
||||
private val lastObservedThreadField = makeField("lastObservedThread")
|
||||
|
||||
companion object {
|
||||
val log by logger
|
||||
const val AGENT_134_CLASS_NAME = "kotlinx.coroutines.debug.CoroutineInfo"
|
||||
const val AGENT_135_AND_UP_CLASS_NAME = "kotlinx.coroutines.debug.internal.DebugCoroutineInfo"
|
||||
|
||||
fun instance(debugProbesImplMirror: DebugProbesImpl, context: DefaultExecutionContext): CoroutineInfo? {
|
||||
val classType = context.findClassSafe(AGENT_134_CLASS_NAME) ?: context.findClassSafe(AGENT_135_AND_UP_CLASS_NAME) ?: return null
|
||||
try {
|
||||
return CoroutineInfo(debugProbesImplMirror, context, classType.name())
|
||||
} catch (e: IllegalStateException) {
|
||||
log.warn("coroutine-debugger: $classType not found", e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCoroutineInfo {
|
||||
val state = objectValue(value, stateMethod, context)?.let {
|
||||
stringValue(it, javaLangMirror.toString, context)
|
||||
}
|
||||
val coroutineContext = coroutineContextMirror.mirror(objectValue(value, contextFieldRef), context)
|
||||
val creationStackBottomObjectReference = objectValue(value, creationStackBottom)
|
||||
val creationStackBottom = coroutineStackFrameMirror.mirror(creationStackBottomObjectReference, context)
|
||||
val creationStackBottom =
|
||||
creationStackBottomObjectReference?.let { CoroutineStackFrame(creationStackBottomObjectReference, context).mirror() }
|
||||
val sequenceNumber = longValue(value, sequenceNumberField)
|
||||
val creationStackTraceList = objectValue(value, creationStackTraceMethod, context)
|
||||
val creationStackTraceMirror = javaLangListMirror.mirror(creationStackTraceList, context)
|
||||
@@ -127,9 +152,9 @@ class CoroutineInfo(val debugProbesImplMirror: DebugProbesImpl, context: Default
|
||||
lastObservedFrame
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
data class MirrorOfCoroutineInfo(
|
||||
val that: ObjectReference,
|
||||
val context: MirrorOfCoroutineContext?,
|
||||
@@ -142,8 +167,8 @@ data class MirrorOfCoroutineInfo(
|
||||
val lastObservedFrame: ObjectReference?
|
||||
)
|
||||
|
||||
class CoroutineStackFrame(context: DefaultExecutionContext) :
|
||||
BaseMirror<MirrorOfCoroutineStackFrame>("kotlin.coroutines.jvm.internal.CoroutineStackFrame", context) {
|
||||
class CoroutineStackFrame(value: ObjectReference, context: DefaultExecutionContext) :
|
||||
BaseDynamicMirror<MirrorOfCoroutineStackFrame>(value, "kotlin.coroutines.jvm.internal.CoroutineStackFrame", context) {
|
||||
private val stackTraceElementMirror = StackTraceElement(context)
|
||||
private val callerFrameMethod = makeMethod("getCallerFrame")
|
||||
private val getStackTraceElementMethod = makeMethod("getStackTraceElement")
|
||||
@@ -151,7 +176,7 @@ class CoroutineStackFrame(context: DefaultExecutionContext) :
|
||||
override fun fetchMirror(value: ObjectReference, context: DefaultExecutionContext): MirrorOfCoroutineStackFrame? {
|
||||
val objectReference = objectValue(value, callerFrameMethod, context)
|
||||
val callerFrame = if (objectReference is ObjectReference)
|
||||
this.mirror(objectReference, context) else null
|
||||
CoroutineStackFrame(objectReference, context).mirror() else null
|
||||
val stackTraceElementReference = objectValue(value, getStackTraceElementMethod, context)
|
||||
val stackTraceElement =
|
||||
if (stackTraceElementReference is ObjectReference) stackTraceElementMirror.mirror(stackTraceElementReference, context) else null
|
||||
|
||||
@@ -9,20 +9,20 @@ 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
|
||||
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
abstract class BaseMirror<T>(val name: String, context: DefaultExecutionContext) {
|
||||
val log by logger
|
||||
protected val cls = context.findClassSafe(name)
|
||||
protected val cls = context.findClassSafe(name) ?: throw IllegalStateException("coroutine-debugger: class $name not found.")
|
||||
|
||||
fun makeField(fieldName: String): Field? =
|
||||
cls?.let { it.fieldByName(fieldName) }
|
||||
|
||||
fun makeMethod(methodName: String): Method? =
|
||||
cls?.let { it.methodsByName(methodName).single() }
|
||||
cls?.let { it.methodsByName(methodName).singleOrNull() }
|
||||
|
||||
fun makeMethod(methodName: String, signature: String): Method? =
|
||||
cls?.let { it.methodsByName(methodName, signature).single() }
|
||||
cls?.let { it.methodsByName(methodName, signature).singleOrNull() }
|
||||
|
||||
fun isCompatible(value: ObjectReference?) =
|
||||
value?.let { it.referenceType().isSubTypeOrSame(name) } ?: false
|
||||
|
||||
@@ -10,9 +10,10 @@ import com.sun.jdi.ClassType
|
||||
import com.sun.jdi.ObjectReference
|
||||
import com.sun.jdi.StringReference
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.isBaseContinuationImpl
|
||||
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.DefaultExecutionContext
|
||||
|
||||
class DebugMetadata internal constructor(context: DefaultExecutionContext) :
|
||||
class DebugMetadata private constructor(context: DefaultExecutionContext) :
|
||||
BaseMirror<MirrorOfDebugProbesImpl>("kotlin.coroutines.jvm.internal.DebugMetadataKt", context) {
|
||||
private val getStackTraceElementMethod = makeMethod("getStackTraceElement")
|
||||
private val getSpilledVariableFieldMappingMethod =
|
||||
@@ -42,10 +43,13 @@ class DebugMetadata internal constructor(context: DefaultExecutionContext) :
|
||||
staticMethodValue(getSpilledVariableFieldMappingMethod, context, value) as? ArrayReference
|
||||
|
||||
companion object {
|
||||
val log by logger
|
||||
|
||||
fun instance(context: DefaultExecutionContext) =
|
||||
try {
|
||||
DebugMetadata(context)
|
||||
} catch (e: IllegalStateException) {
|
||||
log.warn("Attempt to access DebugMetadata", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user