[rd debugger] Wrap topStackFrame into Ref to avoid skipped updates

GitOrigin-RevId: 8a1da442ef7c8cb7de657d8ab18543ccd3d5c19c
This commit is contained in:
Maksim Zuev
2025-09-30 17:13:47 +00:00
committed by intellij-monorepo-bot
parent 646b029992
commit ae318d3386
2 changed files with 15 additions and 38 deletions
@@ -1,28 +0,0 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.xdebugger.impl
import com.intellij.openapi.util.Ref
import com.intellij.xdebugger.frame.XStackFrame
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
/**
* This allows setting current session's [XStackFrame] and updates DB state, when [XStackFrame] is changed.
*/
internal class XDebugSessionCurrentStackFrameManager {
// Ref is used to prevent StateFlow's equals checks
private val currentStackFrame = MutableStateFlow<Ref<XStackFrame?>>(Ref.create(null))
fun setCurrentStackFrame(stackFrame: XStackFrame?) {
currentStackFrame.update {
Ref.create(stackFrame)
}
}
fun getCurrentStackFrame(): XStackFrame? {
return currentStackFrame.value.get()
}
fun getCurrentStackFrameFlow(): StateFlow<Ref<XStackFrame?>> = currentStackFrame
}
@@ -34,6 +34,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.MessageType
import com.intellij.openapi.util.Comparing
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.ThrowableComputable
import com.intellij.platform.kernel.ids.storeValueGlobally
import com.intellij.platform.util.coroutines.childScope
@@ -121,7 +122,6 @@ class XDebugSessionImpl @JvmOverloads constructor(
private var myAlternativeSourceHandler: XAlternativeSourceHandler? = null
private var myIsTopFrame = false
private val myTopStackFrame = MutableStateFlow<XStackFrame?>(null)
private val myPaused = MutableStateFlow(false)
private var myValueMarkers: XValueMarkers<*, *>? = null
private val mySessionName: @Nls String = sessionName
@@ -153,7 +153,12 @@ class XDebugSessionImpl @JvmOverloads constructor(
val extraActions: MutableList<AnAction> = SmartList<AnAction>()
private var myConsoleView: ConsoleView? = null
private val myIcon: Icon? = icon
private val myCurrentStackFrameManager = XDebugSessionCurrentStackFrameManager()
@Volatile
private var currentStackFrame: XStackFrame? = null
// Ref is used to prevent StateFlow's equals checks
private val topStackFrame = MutableStateFlow<Ref<XStackFrame>?>(null)
@get:ApiStatus.Internal
val fileColorsComputer: FileColorsComputer = FileColorsComputer(project, coroutineScope)
@@ -168,7 +173,7 @@ class XDebugSessionImpl @JvmOverloads constructor(
private var myUserRequestAction: String? = null
private val myActiveNonLineBreakpointFlow = myActiveNonLineBreakpointAndPositionFlow
.combine(myTopStackFrame) { breakpointAndPosition, _ ->
.combine(topStackFrame) { breakpointAndPosition, _ ->
val (breakpoint, breakpointPosition) = breakpointAndPosition ?: return@combine null
if (breakpointPosition == null) return@combine breakpoint
val position = topFramePosition ?: return@combine null
@@ -317,7 +322,7 @@ class XDebugSessionImpl @JvmOverloads constructor(
}
override fun getCurrentStackFrame(): XStackFrame? {
return myCurrentStackFrameManager.getCurrentStackFrame()
return currentStackFrame
}
override fun getSuspendContext(): XSuspendContext? {
@@ -329,7 +334,7 @@ class XDebugSessionImpl @JvmOverloads constructor(
}
override fun getTopFramePosition(): XSourcePosition? {
return getFrameSourcePosition(myTopStackFrame.value)
return getFrameSourcePosition(topStackFrame.value?.get())
}
fun getFrameSourcePosition(frame: XStackFrame?): XSourcePosition? {
@@ -770,8 +775,8 @@ class XDebugSessionImpl @JvmOverloads constructor(
currentSuspendCoroutineScope = null
suspendContextFlow.value = null
this.currentExecutionStack = null
myCurrentStackFrameManager.setCurrentStackFrame(null)
myTopStackFrame.value = null
currentStackFrame = null
topStackFrame.value = null
clearActiveNonLineBreakpoint()
updateExecutionPosition()
}
@@ -813,7 +818,7 @@ class XDebugSessionImpl @JvmOverloads constructor(
val frameChanged = currentStackFrame !== frame
this.currentExecutionStack = executionStack
myCurrentStackFrameManager.setCurrentStackFrame(frame)
currentStackFrame = frame
myIsTopFrame = isTopFrame
if (frameChanged) {
@@ -1061,9 +1066,9 @@ class XDebugSessionImpl @JvmOverloads constructor(
this.currentSuspendCoroutineScope = newSuspendContext.coroutineScope ?: provideSuspendScope(this)
this.currentExecutionStack = newSuspendContext.activeExecutionStack
val newCurrentStackFrame = currentExecutionStack?.topFrame
myCurrentStackFrameManager.setCurrentStackFrame(newCurrentStackFrame)
currentStackFrame = newCurrentStackFrame
myIsTopFrame = true
myTopStackFrame.value = newCurrentStackFrame
topStackFrame.value = Ref(newCurrentStackFrame)
val isSteppingSuspendContext = newSuspendContext is XSteppingSuspendContext