mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
[coroutine-debugger]: Removed kotlin-stdlib and coroutines dependencies from intellij.java.rt.iml.
Use simple reflection method calls in the Helper class. GitOrigin-RevId: d260099c7d459e7afcbb544cd7771a49cb97e838
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d37a1c88e7
commit
f5ffbaa42a
@@ -1,27 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.rt.debugger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class CoroutinesDebugHelper {
|
||||
public static long[] getCoroutinesRunningOnCurrentThread(Object debugProbes) throws ReflectiveOperationException {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
List<Long> coroutinesIds = new ArrayList<>();
|
||||
List infos = (List)invoke(debugProbes, "dumpCoroutinesInfo");
|
||||
for (Object info : infos) {
|
||||
if (invoke(info, "getLastObservedThread") == currentThread) {
|
||||
coroutinesIds.add((Long)invoke(info, "getSequenceNumber"));
|
||||
}
|
||||
}
|
||||
long[] res = new long[coroutinesIds.size()];
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
res[i] = coroutinesIds.get(i).longValue();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static Object invoke(Object object, String methodName) throws ReflectiveOperationException {
|
||||
return object.getClass().getMethod(methodName).invoke(object);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.rt.debugger.coroutines;
|
||||
|
||||
|
||||
public final class ContinuationExtractorHelper {
|
||||
private static final String GET_CALLER_FRAME_METHOD = "getCallerFrame";
|
||||
|
||||
public static Object getRootContinuation(Object continuation) throws ReflectiveOperationException {
|
||||
Object parentFrame = invoke(continuation, GET_CALLER_FRAME_METHOD);
|
||||
return (parentFrame != null) ? getRootContinuation(parentFrame) : continuation;
|
||||
}
|
||||
|
||||
private static Object invoke(Object object, String methodName) throws ReflectiveOperationException {
|
||||
return object.getClass().getMethod(methodName).invoke(object);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.rt.debugger.coroutines;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class CoroutinesDebugHelper {
|
||||
|
||||
private static final String GET_CALLER_FRAME_METHOD = "getCallerFrame";
|
||||
private static final String DUMP_COROUTINES_INFO_METHOD = "dumpCoroutinesInfo";
|
||||
private static final String GET_LAST_OBSERVED_THREAD_METHOD = "getLastObservedThread";
|
||||
private static final String GET_SEQUENCE_NUMBER_METHOD = "getSequenceNumber";
|
||||
private static final String COROUTINE_OWNER_CLASS = "CoroutineOwner";
|
||||
private static final String DEBUG_COROUTINE_INFO_FIELD = "info";
|
||||
private static final String SEQUENCE_NUMBER_FIELD = "sequenceNumber";
|
||||
|
||||
public static long[] getCoroutinesRunningOnCurrentThread(Object debugProbes) throws ReflectiveOperationException {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
List<Long> coroutinesIds = new ArrayList<>();
|
||||
List infos = (List)invoke(debugProbes, DUMP_COROUTINES_INFO_METHOD);
|
||||
for (Object info : infos) {
|
||||
if (invoke(info, GET_LAST_OBSERVED_THREAD_METHOD) == currentThread) {
|
||||
coroutinesIds.add((Long)invoke(info, GET_SEQUENCE_NUMBER_METHOD));
|
||||
}
|
||||
}
|
||||
long[] res = new long[coroutinesIds.size()];
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
res[i] = coroutinesIds.get(i).longValue();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static long tryGetContinuationId(Object continuation) throws ReflectiveOperationException {
|
||||
Object rootContinuation = getCoroutineOwner(continuation);
|
||||
Object debugCoroutineInfo = getField(rootContinuation, DEBUG_COROUTINE_INFO_FIELD);
|
||||
return (long) getField(debugCoroutineInfo, SEQUENCE_NUMBER_FIELD);
|
||||
}
|
||||
|
||||
// This method tries to extract CoroutineOwner as a root coroutine frame,
|
||||
// it is invoked when kotlinx-coroutines debug agent is enabled.
|
||||
private static Object getCoroutineOwner(Object stackFrame) throws ReflectiveOperationException {
|
||||
if (stackFrame.getClass().getSimpleName().equals(COROUTINE_OWNER_CLASS)) return stackFrame;
|
||||
Object parentFrame = invoke(stackFrame, GET_CALLER_FRAME_METHOD);
|
||||
return (parentFrame != null) ? getCoroutineOwner(parentFrame) : stackFrame;
|
||||
}
|
||||
|
||||
private static Object getField(Object object, String fieldName) throws ReflectiveOperationException {
|
||||
return object.getClass().getField(fieldName).get(object);
|
||||
}
|
||||
|
||||
private static Object invoke(Object object, String methodName) throws ReflectiveOperationException {
|
||||
return object.getClass().getMethod(methodName).invoke(object);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,8 @@ import com.intellij.execution.ui.layout.impl.RunnerLayoutUiImpl
|
||||
import com.intellij.openapi.application.runInEdt
|
||||
import com.intellij.openapi.diagnostic.thisLogger
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.rt.debugger.CoroutinesDebugHelper
|
||||
import com.intellij.rt.debugger.coroutines.ContinuationExtractorHelper
|
||||
import com.intellij.rt.debugger.coroutines.CoroutinesDebugHelper
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
||||
import com.sun.jdi.*
|
||||
@@ -66,13 +67,13 @@ class CoroutineStackFrameInterceptor : StackFrameInterceptor {
|
||||
// First try to extract Continuation filter
|
||||
val continuationFilter = tryComputeContinuationFilter(frameProxy, defaultExecutionContext)
|
||||
if (continuationFilter != null) return continuationFilter
|
||||
// If continuation could not be extracted or the root continuation was not an instance of BaseContinuationImpl,
|
||||
// If continuation could not be extracted or the root continuation was not an instance of BaseContinuationImpl,
|
||||
// dump coroutines running on the current thread and compute [CoroutineIdFilter].
|
||||
val debugProbesImpl = DebugProbesImpl.instance(defaultExecutionContext)
|
||||
val coroutineIdFilter = if (debugProbesImpl != null && debugProbesImpl.isInstalled) {
|
||||
// first try the helper, it is the fastest way, then try the mirror
|
||||
val currentCoroutines = getCoroutinesRunningOnCurrentThreadFromHelper(defaultExecutionContext, debugProbesImpl) ?:
|
||||
debugProbesImpl.getCoroutinesRunningOnCurrentThread(defaultExecutionContext)
|
||||
val currentCoroutines = getCoroutinesRunningOnCurrentThreadFromHelper(defaultExecutionContext, debugProbesImpl)
|
||||
?: debugProbesImpl.getCoroutinesRunningOnCurrentThread(defaultExecutionContext)
|
||||
CoroutineIdFilter(currentCoroutines)
|
||||
} else {
|
||||
//TODO: IDEA-341142 show nice notification about this
|
||||
@@ -160,32 +161,34 @@ class CoroutineStackFrameInterceptor : StackFrameInterceptor {
|
||||
context: DefaultExecutionContext
|
||||
): CoroutineFilter? {
|
||||
if (debugProbesImpl != null && debugProbesImpl.isInstalled) {
|
||||
val continuationId = (callMethodFromHelper(context, "tryGetContinuationId", listOf(currentContinuation)) as LongValue).value()
|
||||
if (continuationId != -1L) return CoroutineIdFilter(setOf(continuationId))
|
||||
val continuationIdValue = callMethodFromHelper(CoroutinesDebugHelper::class.java, context, "tryGetContinuationId", listOf(currentContinuation))
|
||||
if (continuationIdValue != null) {
|
||||
return CoroutineIdFilter(setOf((continuationIdValue as LongValue).value()))
|
||||
}
|
||||
thisLogger().warn("[coroutine filter]: Could not extract continuation ID, location = ${context.frameProxy?.location()}")
|
||||
}
|
||||
val rootContinuation = callMethodFromHelper(context, "getRootContinuation", listOf(currentContinuation))
|
||||
val rootContinuation = callMethodFromHelper(ContinuationExtractorHelper::class.java, context, "getRootContinuation", listOf(currentContinuation))
|
||||
if (rootContinuation == null) thisLogger().warn("[coroutine filter]: Could not extract continuation instance")
|
||||
return rootContinuation?.let { ContinuationObjectFilter(it as ObjectReference) }
|
||||
}
|
||||
|
||||
|
||||
private fun getCoroutinesRunningOnCurrentThreadFromHelper(
|
||||
context: DefaultExecutionContext,
|
||||
debugProbesImpl: DebugProbesImpl
|
||||
): Set<Long>? {
|
||||
val result = callMethodFromHelper(context, "getCoroutinesRunningOnCurrentThread", listOf(debugProbesImpl.getObject()))
|
||||
val result = callMethodFromHelper(CoroutinesDebugHelper::class.java, context, "getCoroutinesRunningOnCurrentThread", listOf(debugProbesImpl.getObject()))
|
||||
result ?: return null
|
||||
return (result as ArrayReference).values.asSequence().map { (it as LongValue).value() }.toHashSet()
|
||||
}
|
||||
|
||||
private fun callMethodFromHelper(context: DefaultExecutionContext, methodName: String, args: List<Value?>): Value? {
|
||||
private fun callMethodFromHelper(helperClass: Class<*>, context: DefaultExecutionContext, methodName: String, args: List<Value?>): Value? {
|
||||
try {
|
||||
val helperClass = ClassLoadingUtils.getHelperClass(CoroutinesDebugHelper::class.java, context.evaluationContext)
|
||||
if (helperClass != null) {
|
||||
val method = DebuggerUtils.findMethod(helperClass, methodName, null)
|
||||
val helper = ClassLoadingUtils.getHelperClass(helperClass, context.evaluationContext)
|
||||
if (helper != null) {
|
||||
val method = DebuggerUtils.findMethod(helper, methodName, null)
|
||||
if (method != null) {
|
||||
return context.evaluationContext.computeAndKeep {
|
||||
context.invokeMethod(helperClass, method, args)
|
||||
context.invokeMethod(helper, method, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,12 +247,12 @@ class CoroutineStackFrameInterceptor : StackFrameInterceptor {
|
||||
override fun canRunTo(nextCoroutineFilter: CoroutineFilter): Boolean =
|
||||
(nextCoroutineFilter is CoroutineIdFilter && coroutinesRunningOnCurrentThread.intersect(nextCoroutineFilter.coroutinesRunningOnCurrentThread).isNotEmpty())
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The coroutine filter which defines a coroutine by the instance of the Continuation corresponding to the root coroutine frame.
|
||||
*/
|
||||
private data class ContinuationObjectFilter(val reference: ObjectReference) : CoroutineFilter {
|
||||
override fun canRunTo(nextCoroutineFilter: CoroutineFilter): Boolean =
|
||||
override fun canRunTo(nextCoroutineFilter: CoroutineFilter): Boolean =
|
||||
this == nextCoroutineFilter
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user