mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-21 14:01:44 +07:00
[debugger] Coroutine View: fixed coroutine job hierarchy.
Bugs: IDEA-371866, IDEA-366085 Only show the jobs corresponding to the coroutines captured in the dump. GitOrigin-RevId: c163cdcdc9c4ba4d1e25a01daa940ff174af263b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
35763ae892
commit
fd088c015e
@@ -5,9 +5,7 @@ import com.intellij.rt.debugger.JsonUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public final class CoroutinesDebugHelper {
|
||||
|
||||
@@ -170,7 +168,9 @@ public final class CoroutinesDebugHelper {
|
||||
|
||||
/**
|
||||
* This method takes the array of {@link kotlinx.coroutines.debug.internal.DebugCoroutineInfo} instances
|
||||
* and for each coroutine requests it's job, and it's first parent.
|
||||
* and for each coroutine finds it's job and the first parent, which corresponds to some coroutine, captured in the dump.
|
||||
* That means that parent jobs corresponding to ScopeCoroutines (coroutineScope) or DispatchedCoroutine (withContext)
|
||||
* will be skipped. Their frames will be seen in the async stack trace.
|
||||
*
|
||||
* @return an array of Strings of size (debugCoroutineInfos.size * 2), where
|
||||
* (2 * i)-th element is a String representation of the job and
|
||||
@@ -178,7 +178,6 @@ public final class CoroutinesDebugHelper {
|
||||
*/
|
||||
public static String[] getJobsAndParentsForCoroutines(Object ... debugCoroutineInfos) throws ReflectiveOperationException {
|
||||
if (debugCoroutineInfos.length == 0) return new String[]{};
|
||||
String[] jobsWithParents = new String[debugCoroutineInfos.length * 2];
|
||||
ClassLoader loader = debugCoroutineInfos[0].getClass().getClassLoader();
|
||||
Class<?> debugCoroutineInfoClass = Class.forName(DEBUG_COROUTINE_INFO_FQN, false, loader);
|
||||
Class<?> coroutineContext = Class.forName(COROUTINE_CONTEXT_FQN, false, loader);
|
||||
@@ -189,20 +188,33 @@ public final class CoroutinesDebugHelper {
|
||||
Method getParentJob = coroutineJobClass.getMethod("getParent");
|
||||
Method getContext = debugCoroutineInfoClass.getMethod("getContext");
|
||||
|
||||
for (int i = 0; i < debugCoroutineInfos.length * 2; i += 2) {
|
||||
Object info = debugCoroutineInfos[i / 2];
|
||||
if (info == null) {
|
||||
jobsWithParents[i] = null;
|
||||
jobsWithParents[i + 1] = null;
|
||||
continue;
|
||||
}
|
||||
String[] jobToCapturedParent = new String[debugCoroutineInfos.length * 2];
|
||||
Set<String> capturedJobs = new HashSet<>();
|
||||
for(Object info : debugCoroutineInfos) {
|
||||
Object context = invoke(info, getContext);
|
||||
Object job = invoke(context, coroutineContextGet, coroutineJobKey);
|
||||
Object parent = invoke(job, getParentJob);
|
||||
jobsWithParents[i] = (job == null) ? null : job.toString();
|
||||
jobsWithParents[i + 1] = (parent == null) ? null : parent.toString();
|
||||
capturedJobs.add(job.toString());
|
||||
}
|
||||
return jobsWithParents;
|
||||
for (int i = 0; i < debugCoroutineInfos.length * 2; i += 2) {
|
||||
Object info = debugCoroutineInfos[i / 2];
|
||||
Object context = invoke(info, getContext);
|
||||
Object job = invoke(context, coroutineContextGet, coroutineJobKey);
|
||||
if (job == null) {
|
||||
jobToCapturedParent[i] = null;
|
||||
jobToCapturedParent[i + 1] = null;
|
||||
continue;
|
||||
}
|
||||
jobToCapturedParent[i] = job.toString();
|
||||
Object parent = invoke(job, getParentJob);
|
||||
while (parent != null) {
|
||||
if (capturedJobs.contains(parent.toString())) {
|
||||
jobToCapturedParent[i + 1] = parent.toString();
|
||||
break;
|
||||
}
|
||||
parent = invoke(parent, getParentJob);
|
||||
}
|
||||
}
|
||||
return jobToCapturedParent;
|
||||
}
|
||||
|
||||
private static Object getField(Object object, String fieldName) throws ReflectiveOperationException {
|
||||
|
||||
@@ -46,6 +46,9 @@ class CoroutineDebugProbesProxy(val suspendContext: SuspendContextImpl) {
|
||||
* array[2 * i] = info.job
|
||||
* array[2 * i + 1] = info.parent
|
||||
*
|
||||
* NOTE: only coroutines which are captured in the coroutine dump will be shown in the Coroutine View,
|
||||
* jobs which do not correspond to any captured coroutine will not be shown (e.g., jobs of completing coroutines or scope coroutines).
|
||||
*
|
||||
* The corresponding properties [CoroutineInfoData.job] and [CoroutineInfoData.parentJob] are set to the obtained values.
|
||||
*/
|
||||
internal fun fetchAndSetJobsAndParentsForCoroutines(infos: List<CoroutineInfoData>): Boolean {
|
||||
|
||||
@@ -183,16 +183,7 @@ internal class CoroutineView(project: Project, javaDebugProcess: JavaDebugProces
|
||||
if (isHierarchyBuilt) {
|
||||
val parentJobToChildCoroutineInfos = cache.groupBy { it.parentJob }
|
||||
val jobToCoroutineInfo = cache.associateBy { it.job }
|
||||
val parentJobs = parentJobToChildCoroutineInfos.keys
|
||||
val rootJobs = parentJobs.mapNotNull {
|
||||
// The root job's coroutine is either not present in the dump (and in jobToCoroutineInfo map)
|
||||
// (e.g. if it's a BlockingCoroutine, which was not captured in the coroutine dump, because it's already completing).
|
||||
// or it has no parent.
|
||||
val parentCoroutineInfo = jobToCoroutineInfo[it]
|
||||
if (parentCoroutineInfo == null || parentCoroutineInfo.parentJob == null) {
|
||||
it
|
||||
} else null
|
||||
}
|
||||
val rootJobs = cache.filter { it.parentJob == null }.mapNotNull { it.job }
|
||||
for (rootJob in rootJobs) {
|
||||
val rootCoroutine = jobToCoroutineInfo[rootJob]
|
||||
coroutines.add(
|
||||
|
||||
Reference in New Issue
Block a user