mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[debugger] IDEA-376098 Compute stack frame position asynchronously
GitOrigin-RevId: ae65f2306ec402f1163e0a10449d550e24b7a27c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8bd029b85b
commit
4a99c1ffd0
@@ -28,6 +28,7 @@ import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.sun.jdi.Location
|
||||
import com.sun.jdi.ReferenceType
|
||||
import com.sun.jdi.request.ClassPrepareRequest
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
@@ -159,23 +160,40 @@ class CompoundPositionManager() : PositionManagerWithConditionEvaluation, MultiR
|
||||
}
|
||||
}!!
|
||||
|
||||
fun createStackFrames(descriptor: StackFrameDescriptorImpl): MutableList<XStackFrame>? =
|
||||
iterate(null, null, ProgressManager::checkCanceled) {
|
||||
if (it is PositionManagerWithMultipleStackFrames) {
|
||||
val stackFrames = it.createStackFrames(descriptor)
|
||||
if (stackFrames != null) {
|
||||
return@iterate stackFrames
|
||||
}
|
||||
}
|
||||
else if (it is PositionManagerEx) {
|
||||
val xStackFrame = it.createStackFrame(descriptor)
|
||||
if (xStackFrame != null) {
|
||||
return@iterate mutableListOf(xStackFrame)
|
||||
}
|
||||
}
|
||||
throw NoDataException.INSTANCE
|
||||
@ApiStatus.Internal
|
||||
fun createStackFrames(descriptor: StackFrameDescriptorImpl): List<XStackFrame>? =
|
||||
iterate(null, null, ProgressManager::checkCanceled) { positionManager ->
|
||||
createStackFramesInternal(positionManager, descriptor) { createStackFrames(it) }
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun createStackFramesAsync(descriptor: StackFrameDescriptorImpl): CompletableFuture<List<XStackFrame>?> =
|
||||
invokeCommandAsCompletableFuture {
|
||||
iterate(null, null, { checkCanceled() }) { positionManager ->
|
||||
createStackFramesInternal(positionManager, descriptor) { createStackFramesAsync(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun createStackFramesInternal(
|
||||
manager: PositionManager,
|
||||
descriptor: StackFrameDescriptorImpl,
|
||||
extractMultipleFrames: PositionManagerWithMultipleStackFrames.(StackFrameDescriptorImpl) -> List<XStackFrame>?,
|
||||
): List<XStackFrame> {
|
||||
if (manager is PositionManagerWithMultipleStackFrames) {
|
||||
val stackFrames = manager.extractMultipleFrames(descriptor)
|
||||
if (stackFrames != null) {
|
||||
return stackFrames
|
||||
}
|
||||
}
|
||||
else if (manager is PositionManagerEx) {
|
||||
val xStackFrame = manager.createStackFrame(descriptor)
|
||||
if (xStackFrame != null) {
|
||||
return mutableListOf(xStackFrame)
|
||||
}
|
||||
}
|
||||
throw NoDataException.INSTANCE
|
||||
}
|
||||
|
||||
override fun evaluateCondition(
|
||||
context: EvaluationContext,
|
||||
frame: StackFrameProxyImpl,
|
||||
|
||||
@@ -158,17 +158,11 @@ public class JavaExecutionStack extends XExecutionStack {
|
||||
}
|
||||
|
||||
return StackFrameDescriptorImpl.createAsync(stackFrameProxy, myTracker)
|
||||
.thenApply(this::createFrames);
|
||||
.thenCompose(this::createFramesAsync);
|
||||
}
|
||||
|
||||
private @NotNull List<XStackFrame> createFrames(StackFrameDescriptorImpl descriptor) {
|
||||
XStackFrame topFrame = ContainerUtil.getFirstItem(myTopFrames);
|
||||
if (descriptor.getUiIndex() == 1 && topFrame instanceof JavaStackFrame) {
|
||||
Method method = descriptor.getMethod();
|
||||
if (method != null) {
|
||||
((JavaStackFrame)topFrame).getDescriptor().putUserData(BreakpointIntentionAction.CALLER_KEY, DebuggerUtilsEx.methodKey(method));
|
||||
}
|
||||
}
|
||||
markCallerFrame(descriptor);
|
||||
|
||||
List<XStackFrame> customFrames = myDebugProcess.getPositionManager().createStackFrames(descriptor);
|
||||
if (customFrames != null) {
|
||||
@@ -178,6 +172,28 @@ public class JavaExecutionStack extends XExecutionStack {
|
||||
return Collections.singletonList(new JavaStackFrame(descriptor, true));
|
||||
}
|
||||
|
||||
private @NotNull CompletableFuture<@NotNull List<XStackFrame>> createFramesAsync(StackFrameDescriptorImpl descriptor) {
|
||||
markCallerFrame(descriptor);
|
||||
|
||||
return myDebugProcess.getPositionManager().createStackFramesAsync(descriptor)
|
||||
.thenApply(customFrames -> {
|
||||
if (customFrames != null) {
|
||||
return customFrames;
|
||||
}
|
||||
return Collections.singletonList(new JavaStackFrame(descriptor, true));
|
||||
});
|
||||
}
|
||||
|
||||
private void markCallerFrame(StackFrameDescriptorImpl descriptor) {
|
||||
XStackFrame topFrame = ContainerUtil.getFirstItem(myTopFrames);
|
||||
if (descriptor.getUiIndex() == 1 && topFrame instanceof JavaStackFrame) {
|
||||
Method method = descriptor.getMethod();
|
||||
if (method != null) {
|
||||
((JavaStackFrame)topFrame).getDescriptor().putUserData(BreakpointIntentionAction.CALLER_KEY, DebuggerUtilsEx.methodKey(method));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable XStackFrame getTopFrame() {
|
||||
return ContainerUtil.getFirstItem(myTopFrames);
|
||||
|
||||
@@ -3,10 +3,7 @@ package com.intellij.debugger.engine
|
||||
|
||||
import com.intellij.debugger.PositionManager
|
||||
import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.fileLogger
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.debugger.impl.runBlockingAssertNotInReadAction
|
||||
import com.intellij.util.concurrency.annotations.RequiresBlockingContext
|
||||
import com.sun.jdi.Location
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
@@ -17,12 +14,7 @@ interface PositionManagerAsync : PositionManager {
|
||||
|
||||
@RequiresBlockingContext
|
||||
override fun getSourcePosition(location: Location?): SourcePosition? {
|
||||
if (ApplicationManager.getApplication().isInternal
|
||||
&& ApplicationManager.getApplication().isReadAccessAllowed
|
||||
&& !ProgressManager.getInstance().hasProgressIndicator()) {
|
||||
fileLogger().error("Call runBlocking from read action without indicator")
|
||||
}
|
||||
return runBlockingMaybeCancellable {
|
||||
return runBlockingAssertNotInReadAction {
|
||||
getSourcePositionAsync(location)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-9
@@ -1,19 +1,21 @@
|
||||
// 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.debugger.engine;
|
||||
package com.intellij.debugger.engine
|
||||
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
|
||||
import com.intellij.xdebugger.frame.XStackFrame;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.intellij.debugger.impl.runBlockingAssertNotInReadAction
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
|
||||
import java.util.List;
|
||||
interface PositionManagerWithMultipleStackFrames : PositionManagerWithConditionEvaluation {
|
||||
@Deprecated("Use createStackFramesAsync instead")
|
||||
fun createStackFrames(descriptor: StackFrameDescriptorImpl): List<XStackFrame>? {
|
||||
return runBlockingAssertNotInReadAction { createStackFramesAsync(descriptor) }
|
||||
}
|
||||
|
||||
public interface PositionManagerWithMultipleStackFrames extends PositionManagerWithConditionEvaluation {
|
||||
/**
|
||||
* Allows to replace a jvm frame with one or several frames, or skip a frame
|
||||
* @return a list of frames to replace the original frame with, or null to use the default mapping
|
||||
*/
|
||||
default @Nullable List<XStackFrame> createStackFrames(@NotNull StackFrameDescriptorImpl descriptor) {
|
||||
return null;
|
||||
suspend fun createStackFramesAsync(descriptor: StackFrameDescriptorImpl): List<XStackFrame>? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,16 @@ import com.intellij.debugger.engine.DebugProcessEvents
|
||||
import com.intellij.debugger.engine.DebuggerManagerThreadImpl
|
||||
import com.intellij.debugger.engine.DebuggerUtils
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.fileLogger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.sun.jdi.*
|
||||
import com.sun.jdi.event.ClassPrepareEvent
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.consumeEach
|
||||
import kotlinx.coroutines.future.await
|
||||
@@ -118,3 +122,12 @@ fun preloadAllClasses(vm: VirtualMachine) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> runBlockingAssertNotInReadAction(block: suspend CoroutineScope.() -> T): T {
|
||||
if (ApplicationManager.getApplication().isInternal
|
||||
&& ApplicationManager.getApplication().isReadAccessAllowed
|
||||
&& !ProgressManager.getInstance().hasProgressIndicator()) {
|
||||
fileLogger().error("Call runBlocking from read action without indicator")
|
||||
}
|
||||
return runBlockingMaybeCancellable(block)
|
||||
}
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ class KotlinPositionManager(private val debugProcess: DebugProcess) : MultiReque
|
||||
return ThreeState.UNSURE
|
||||
}
|
||||
|
||||
override fun createStackFrames(descriptor: StackFrameDescriptorImpl): List<XStackFrame>? {
|
||||
override suspend fun createStackFramesAsync(descriptor: StackFrameDescriptorImpl): List<XStackFrame>? {
|
||||
DebuggerManagerThreadImpl.assertIsManagerThread()
|
||||
if (descriptor.location?.isInKotlinSources() != true) {
|
||||
return null
|
||||
|
||||
+3
-1
@@ -8,10 +8,12 @@ import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.openapi.components.serviceOrNull
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.sun.jdi.Location
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.kotlin.idea.debugger.core.stepping.CoroutineFilter
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface StackFrameInterceptor {
|
||||
fun createStackFrames(
|
||||
suspend fun createStackFrames(
|
||||
frame: StackFrameProxyImpl,
|
||||
debugProcess: DebugProcessImpl
|
||||
): List<XStackFrame>?
|
||||
|
||||
+5
-2
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.idea.debugger.coroutine.util.*
|
||||
|
||||
|
||||
private class CoroutineStackFrameInterceptor : StackFrameInterceptor {
|
||||
override fun createStackFrames(frame: StackFrameProxyImpl, debugProcess: DebugProcessImpl): List<XStackFrame>? {
|
||||
override suspend fun createStackFrames(frame: StackFrameProxyImpl, debugProcess: DebugProcessImpl): List<XStackFrame>? {
|
||||
DebuggerManagerThreadImpl.assertIsManagerThread()
|
||||
if (debugProcess.xdebugProcess?.session !is XDebugSessionImpl
|
||||
|| frame is SkipCoroutineStackFrameProxyImpl
|
||||
@@ -75,7 +75,10 @@ private class CoroutineStackFrameInterceptor : StackFrameInterceptor {
|
||||
return listOf(stackFrame)
|
||||
}
|
||||
val frameItemLists = CoroutineFrameBuilder.build(stackFrame, withPreFrames = false)
|
||||
return listOf(stackFrame) + frameItemLists.frames.mapNotNull { it.createFrame(debugProcess) }
|
||||
return listOf(stackFrame) + frameItemLists.frames.mapNotNull {
|
||||
val sourcePosition = debugProcess.positionManager.getSourcePositionAsync(it.location)
|
||||
it.createFrame(debugProcess, sourcePosition)
|
||||
}
|
||||
}
|
||||
|
||||
private fun anySuspendFramesBefore(frame: StackFrameProxyImpl): Boolean {
|
||||
|
||||
Reference in New Issue
Block a user