diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinCoroutinesAsyncStackTraceProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinCoroutinesAsyncStackTraceProvider.kt index 47fc8404ecd..a8a016865e3 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinCoroutinesAsyncStackTraceProvider.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinCoroutinesAsyncStackTraceProvider.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.debugger import com.intellij.debugger.DebuggerContext +import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.JavaStackFrame import com.intellij.debugger.engine.JavaValue import com.intellij.debugger.engine.SuspendContextImpl @@ -13,6 +14,7 @@ import com.intellij.debugger.engine.evaluation.EvaluateException import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import com.intellij.debugger.jdi.GeneratedLocation import com.intellij.debugger.jdi.StackFrameProxyImpl +import com.intellij.debugger.jdi.VirtualMachineProxyImpl import com.intellij.debugger.memory.utils.StackFrameItem import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl import com.intellij.xdebugger.frame.XNamedValue @@ -20,21 +22,21 @@ import com.sun.jdi.* import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_VARIABLE_NAME import org.jetbrains.kotlin.idea.debugger.evaluate.LOG import org.jetbrains.kotlin.idea.debugger.evaluate.variables.VariableFinder.Companion.SUSPEND_LAMBDA_CLASSES -import org.jetbrains.kotlin.idea.debugger.evaluate.getInvokePolicy import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull class KotlinCoroutinesAsyncStackTraceProvider : KotlinCoroutinesAsyncStackTraceProviderBase { private companion object { const val DEBUG_METADATA_KT = "kotlin.coroutines.jvm.internal.DebugMetadataKt" - fun classByName(name: String, frame: StackFrameProxyImpl, threadReference: ThreadReference, invokePolicy: Int): ReferenceType? { - val virtualMachine = frame.virtualMachine + fun ContextBase.classByName(name: String): ReferenceType? { val classClass = virtualMachine.classesByName(Class::class.java.name).firstIsInstanceOrNull() ?: return null - val forNameMethod = classClass.methodsByName("forName").first { it.signature() == "(Ljava/lang/String;)Ljava/lang/Class;" } + val forNameMethod = classClass.methodsByName("forName") + .firstOrNull { it.signature() == "(Ljava/lang/String;)Ljava/lang/Class;" } + ?: return null try { val args = listOf(virtualMachine.mirrorOf(name)) - val result = classClass.invokeMethod(threadReference, forNameMethod, args, invokePolicy) + val result = debugProcess.invokeMethod(evaluationContext, classClass, forNameMethod, args) if (result is ClassObjectReference) { return result.reflectedType() @@ -64,11 +66,14 @@ class KotlinCoroutinesAsyncStackTraceProvider : KotlinCoroutinesAsyncStackTraceP fun getAsyncStackTrace(frameProxy: StackFrameProxyImpl, suspendContext: SuspendContextImpl): List? { val location = frameProxy.location() val method = location.safeMethod() ?: return null - val threadReference = frameProxy.threadProxy().threadReference.takeIf { it.isSuspended && it.isAtBreakpoint } ?: return null - val invokePolicy = suspendContext.getInvokePolicy() - val debugMetadataKtType = classByName(DEBUG_METADATA_KT, frameProxy, threadReference, invokePolicy) as? ClassType ?: return null + val currentThread = frameProxy.threadProxy().threadReference + if (currentThread == null || !currentThread.isSuspended || !currentThread.isAtBreakpoint) { + return null + } + val contextBase = ContextBase(suspendContext, frameProxy) + val debugMetadataKtType = contextBase.classByName(DEBUG_METADATA_KT) as? ClassType ?: return null - val context = Context(suspendContext, frameProxy, method, debugMetadataKtType, threadReference, invokePolicy) + val context = Context(suspendContext, frameProxy, method, debugMetadataKtType) return context.getAsyncStackTraceForSuspendLambda() ?: context.getAsyncStackTraceForSuspendFunction() } @@ -120,16 +125,20 @@ class KotlinCoroutinesAsyncStackTraceProvider : KotlinCoroutinesAsyncStackTraceP collectFramesRecursively(completion, consumer) } - private class Context( - val suspendContext: SuspendContextImpl, - val frameProxy: StackFrameProxyImpl, - val method: Method, - private val debugMetadataKtType: ClassType, - private val threadReference: ThreadReference, - private val invokePolicy: Int - ) { - val evaluationContext: EvaluationContextImpl by lazy { EvaluationContextImpl(suspendContext, frameProxy) } + private open class ContextBase(val suspendContext: SuspendContextImpl, val frameProxy: StackFrameProxyImpl) { + val virtualMachine: VirtualMachineProxyImpl + get() = frameProxy.virtualMachine + val debugProcess: DebugProcessImpl + get() = suspendContext.debugProcess + + val evaluationContext: EvaluationContextImpl by lazy { EvaluationContextImpl(suspendContext, frameProxy) } + } + + private class Context( + suspendContext: SuspendContextImpl, frameProxy: StackFrameProxyImpl, + val method: Method, private val debugMetadataKtType: ClassType + ) : ContextBase(suspendContext, frameProxy) { fun getLocation(continuation: ObjectReference): Location? { val getStackTraceElementMethod = debugMetadataKtType.methodsByName( "getStackTraceElement", @@ -138,22 +147,23 @@ class KotlinCoroutinesAsyncStackTraceProvider : KotlinCoroutinesAsyncStackTraceP val args = listOf(continuation) - val stackTraceElement = debugMetadataKtType - .invokeMethod(threadReference, getStackTraceElementMethod, args, invokePolicy) as? ObjectReference ?: return null + val stackTraceElement = debugProcess + .invokeMethod(evaluationContext, debugMetadataKtType, getStackTraceElementMethod, args) as? ObjectReference + ?: return null val stackTraceElementType = stackTraceElement.referenceType().takeIf { it.name() == StackTraceElement::class.java.name } ?: return null fun getValue(name: String, desc: String): Value? { val method = stackTraceElementType.methodsByName(name, desc).single() - return stackTraceElement.invokeMethod(threadReference, method, emptyList(), invokePolicy) + return debugProcess.invokeMethod(evaluationContext, stackTraceElement, method, emptyList()) } val className = (getValue("getClassName", "()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 locationClass = classByName(className, frameProxy, threadReference, invokePolicy) ?: return null + val locationClass = classByName(className) ?: return null return GeneratedLocation(suspendContext.debugProcess, locationClass, methodName, lineNumber) } @@ -165,8 +175,9 @@ class KotlinCoroutinesAsyncStackTraceProvider : KotlinCoroutinesAsyncStackTraceP val args = listOf(continuation) - val rawSpilledVariables = debugMetadataKtType - .invokeMethod(threadReference, getSpilledVariableFieldMappingMethod, args, invokePolicy) as? ArrayReference ?: return null + val rawSpilledVariables = debugProcess + .invokeMethod(evaluationContext, debugMetadataKtType, getSpilledVariableFieldMappingMethod, args) as? ArrayReference + ?: return null val length = rawSpilledVariables.length() / 2 val spilledVariables = ArrayList(length) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/ExecutionContext.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/ExecutionContext.kt index 70ae61c21b7..800a65ba9e1 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/ExecutionContext.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/ExecutionContext.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.debugger.evaluate +import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import com.sun.jdi.* import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull @@ -14,6 +15,9 @@ class ExecutionContext(val evaluationContext: EvaluationContextImpl, val thread: val vm: VirtualMachine get() = thread.virtualMachine() + val debugProcess: DebugProcessImpl + get() = evaluationContext.debugProcess + fun loadClassType(asmType: Type, classLoader: ClassLoaderReference? = null): ReferenceType? { if (asmType.sort == Type.ARRAY) { return loadClassType(asmType.elementType, classLoader) @@ -43,7 +47,8 @@ class ExecutionContext(val evaluationContext: EvaluationContextImpl, val thread: return null } - return (classClass.invokeMethod(thread, method, args, invokePolicy) as? ClassObjectReference)?.reflectedType() + val result = evaluationContext.debugProcess.invokeMethod(evaluationContext, classClass, method, args) + return (result as? ClassObjectReference)?.reflectedType() } } \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt index 42251c4e150..5b367f9ebf7 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -288,7 +288,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour val mainClassType = context.loadClassType(Type.getObjectType(GENERATED_CLASS_NAME), classLoader) as? ClassType ?: error("Can not find class \"$GENERATED_CLASS_NAME\"") val mainMethod = mainClassType.methods().single { it.name() == GENERATED_FUNCTION_NAME } - val returnValue = mainClassType.invokeMethod(context.thread, mainMethod, args, context.invokePolicy) + val returnValue = context.debugProcess.invokeMethod(context.evaluationContext, mainClassType, mainMethod, args) EvaluatorValueConverter(context).unref(returnValue) } } catch (e: Throwable) { diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/EvaluatorValueConverter.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/EvaluatorValueConverter.kt index d729ecc6f95..f30c9d960ba 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/EvaluatorValueConverter.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/EvaluatorValueConverter.kt @@ -136,7 +136,9 @@ class EvaluatorValueConverter(private val executionContext: ExecutionContext) { val methodDesc = AsmType.getMethodDescriptor(boxedType, unboxedType) val valueOfMethod = boxedTypeClass.methodsByName("valueOf", methodDesc).first() - return boxedTypeClass.invokeMethod(executionContext.thread, valueOfMethod, listOf(value), executionContext.invokePolicy) + + val debugProcess = executionContext.evaluationContext.debugProcess + return debugProcess.invokeMethod(executionContext.evaluationContext, boxedTypeClass, valueOfMethod, listOf(value)) } private fun unbox(value: Value?): Value? { @@ -151,7 +153,7 @@ class EvaluatorValueConverter(private val executionContext: ExecutionContext) { val unboxingMethodName = UNBOXING_METHOD_NAMES.getValue(boxedType.internalName) val methodDesc = AsmType.getMethodDescriptor(unboxedType) val valueMethod = boxedTypeClass.methodsByName(unboxingMethodName, methodDesc).first() - return value.invokeMethod(executionContext.thread, valueMethod, emptyList(), executionContext.invokePolicy) + return executionContext.debugProcess.invokeMethod(executionContext.evaluationContext, value, valueMethod, emptyList()) } private fun ref(value: Value?): Value? { diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt index 8c07f2d71e5..2a2ff1457e6 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/variables/VariableFinder.kt @@ -408,7 +408,7 @@ class VariableFinder private constructor(private val context: ExecutionContext, .methodsByName("getContext", "()Lkotlin/coroutines/CoroutineContext;").firstOrNull() ?: return null - return continuation.invokeMethod(context.thread, getContextMethod, emptyList(), context.invokePolicy) as? ObjectReference + return context.debugProcess.invokeMethod(context.evaluationContext, continuation, getContextMethod, emptyList()) as? ObjectReference } private fun findCapturedVariableInReceiver(variables: List, kind: VariableKind): Result? { @@ -482,7 +482,7 @@ class VariableFinder private constructor(private val context: ExecutionContext, .methodsByName("getValue", "()Ljava/lang/Object;").firstOrNull() ?: return rawValue - return delegateValue.invokeMethod(context.thread, getValueMethod, emptyList(), context.invokePolicy) + return context.debugProcess.invokeMethod(context.evaluationContext, delegateValue, getValueMethod, emptyList()) } private fun isCapturedReceiverFieldName(name: String): Boolean {