Coroutine stack trace provider: check thread state before invokeMethod()

This commit is contained in:
Yan Zhulanow
2019-02-02 00:37:31 +03:00
parent 24cdd3f857
commit 51b26325c6
@@ -28,15 +28,14 @@ class KotlinCoroutinesAsyncStackTraceProvider : AsyncStackTraceProvider {
private companion object { private companion object {
const val DEBUG_METADATA_KT = "kotlin.coroutines.jvm.internal.DebugMetadataKt" const val DEBUG_METADATA_KT = "kotlin.coroutines.jvm.internal.DebugMetadataKt"
fun classByName(name: String, frameProxy: StackFrameProxyImpl, suspendContext: SuspendContextImpl): ReferenceType? { fun classByName(name: String, frame: StackFrameProxyImpl, threadReference: ThreadReference, invokePolicy: Int): ReferenceType? {
val virtualMachine = frameProxy.virtualMachine val virtualMachine = frame.virtualMachine
val classClass = virtualMachine.classesByName(Class::class.java.name).firstIsInstanceOrNull<ClassType>() ?: return null val classClass = virtualMachine.classesByName(Class::class.java.name).firstIsInstanceOrNull<ClassType>() ?: return null
val forNameMethod = classClass.methodsByName("forName").first { it.signature() == "(Ljava/lang/String;)Ljava/lang/Class;" } val forNameMethod = classClass.methodsByName("forName").first { it.signature() == "(Ljava/lang/String;)Ljava/lang/Class;" }
try { try {
val threadReference = frameProxy.threadProxy().threadReference
val args = listOf(virtualMachine.mirrorOf(name)) val args = listOf(virtualMachine.mirrorOf(name))
val result = classClass.invokeMethod(threadReference, forNameMethod, args, suspendContext.getInvokePolicy()) val result = classClass.invokeMethod(threadReference, forNameMethod, args, invokePolicy)
if (result is ClassObjectReference) { if (result is ClassObjectReference) {
return result.reflectedType() return result.reflectedType()
@@ -66,9 +65,11 @@ class KotlinCoroutinesAsyncStackTraceProvider : AsyncStackTraceProvider {
fun getAsyncStackTrace(frameProxy: StackFrameProxyImpl, suspendContext: SuspendContextImpl): List<StackFrameItem>? { fun getAsyncStackTrace(frameProxy: StackFrameProxyImpl, suspendContext: SuspendContextImpl): List<StackFrameItem>? {
val location = frameProxy.location() val location = frameProxy.location()
val method = location.safeMethod() ?: return null val method = location.safeMethod() ?: return null
val debugMetadataKtType = classByName(DEBUG_METADATA_KT, frameProxy, suspendContext) as? ClassType ?: return null val threadReference = frameProxy.threadProxy().threadReference.takeIf { it.isSuspended } ?: return null
val invokePolicy = suspendContext.getInvokePolicy()
val debugMetadataKtType = classByName(DEBUG_METADATA_KT, frameProxy, threadReference, invokePolicy) as? ClassType ?: return null
val context = Context(suspendContext, frameProxy, method, debugMetadataKtType) val context = Context(suspendContext, frameProxy, method, debugMetadataKtType, threadReference, invokePolicy)
return context.getAsyncStackTraceForSuspendLambda() ?: context.getAsyncStackTraceForSuspendFunction() return context.getAsyncStackTraceForSuspendLambda() ?: context.getAsyncStackTraceForSuspendFunction()
} }
@@ -124,7 +125,9 @@ class KotlinCoroutinesAsyncStackTraceProvider : AsyncStackTraceProvider {
val suspendContext: SuspendContextImpl, val suspendContext: SuspendContextImpl,
val frameProxy: StackFrameProxyImpl, val frameProxy: StackFrameProxyImpl,
val method: Method, val method: Method,
private val debugMetadataKtType: ClassType private val debugMetadataKtType: ClassType,
private val threadReference: ThreadReference,
private val invokePolicy: Int
) { ) {
val evaluationContext: EvaluationContextImpl by lazy { EvaluationContextImpl(suspendContext, frameProxy) } val evaluationContext: EvaluationContextImpl by lazy { EvaluationContextImpl(suspendContext, frameProxy) }
@@ -134,9 +137,7 @@ class KotlinCoroutinesAsyncStackTraceProvider : AsyncStackTraceProvider {
"(Lkotlin/coroutines/jvm/internal/BaseContinuationImpl;)Ljava/lang/StackTraceElement;" "(Lkotlin/coroutines/jvm/internal/BaseContinuationImpl;)Ljava/lang/StackTraceElement;"
).firstOrNull() ?: return null ).firstOrNull() ?: return null
val threadReference = frameProxy.threadProxy().threadReference.takeIf { it.isSuspended } ?: return null
val args = listOf(continuation) val args = listOf(continuation)
val invokePolicy = suspendContext.getInvokePolicy()
val stackTraceElement = debugMetadataKtType val stackTraceElement = debugMetadataKtType
.invokeMethod(threadReference, getStackTraceElementMethod, args, invokePolicy) as? ObjectReference ?: return null .invokeMethod(threadReference, getStackTraceElementMethod, args, invokePolicy) as? ObjectReference ?: return null
@@ -153,7 +154,7 @@ class KotlinCoroutinesAsyncStackTraceProvider : AsyncStackTraceProvider {
val methodName = (getValue("getMethodName", "()Ljava/lang/String;") as? StringReference)?.value() ?: return null val methodName = (getValue("getMethodName", "()Ljava/lang/String;") as? StringReference)?.value() ?: return null
val lineNumber = (getValue("getLineNumber", "()I") as? IntegerValue)?.value()?.takeIf { it >= 0 } ?: return null val lineNumber = (getValue("getLineNumber", "()I") as? IntegerValue)?.value()?.takeIf { it >= 0 } ?: return null
val locationClass = classByName(className, frameProxy, suspendContext) ?: return null val locationClass = classByName(className, frameProxy, threadReference, invokePolicy) ?: return null
return GeneratedLocation(suspendContext.debugProcess, locationClass, methodName, lineNumber) return GeneratedLocation(suspendContext.debugProcess, locationClass, methodName, lineNumber)
} }
@@ -163,9 +164,7 @@ class KotlinCoroutinesAsyncStackTraceProvider : AsyncStackTraceProvider {
"(Lkotlin/coroutines/jvm/internal/BaseContinuationImpl;)[Ljava/lang/String;" "(Lkotlin/coroutines/jvm/internal/BaseContinuationImpl;)[Ljava/lang/String;"
).firstOrNull() ?: return null ).firstOrNull() ?: return null
val threadReference = frameProxy.threadProxy().threadReference.takeIf { it.isSuspended } ?: return null
val args = listOf(continuation) val args = listOf(continuation)
val invokePolicy = suspendContext.getInvokePolicy()
val rawSpilledVariables = debugMetadataKtType val rawSpilledVariables = debugMetadataKtType
.invokeMethod(threadReference, getSpilledVariableFieldMappingMethod, args, invokePolicy) as? ArrayReference ?: return null .invokeMethod(threadReference, getSpilledVariableFieldMappingMethod, args, invokePolicy) as? ArrayReference ?: return null