IDEA-374699 [debugger] Avoid excessive deduplication

As was described in  137fc9538070237f44c0868d9b947bb66d514bb1, frames are never compared by value.

GitOrigin-RevId: fe8f1f11a29b39fd282dfc1acd97cd14e3dd1184
This commit is contained in:
Alexander Kuznetsov
2025-06-20 14:29:09 +00:00
committed by intellij-monorepo-bot
parent 6703b2fb25
commit c6633afda0
3 changed files with 26 additions and 16 deletions
@@ -9,7 +9,8 @@ import com.intellij.platform.util.coroutines.childScope
import com.intellij.ui.ColoredTextContainer
import com.intellij.xdebugger.frame.XStackFrame
import com.intellij.xdebugger.frame.XStackFrameUiPresentationContainer
import fleet.multiplatform.shims.ConcurrentHashMap
import com.intellij.xdebugger.impl.util.identityConcurrentHashMap
import com.intellij.xdebugger.impl.util.identityWrapper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
@@ -31,14 +32,14 @@ class XFramesAsyncPresentationManager(private val cs: CoroutineScope) {
class XFramesAsyncPresentationHandler(private val framesList: XDebuggerFramesList, private val cs: CoroutineScope) {
private val cache = ConcurrentHashMap<XStackFrame, XStackFrameUiPresentationContainer>()
private val cache = identityConcurrentHashMap<XStackFrame, XStackFrameUiPresentationContainer>()
private val repaintRequests = MutableSharedFlow<Unit>()
fun scheduleForFrames(stackFrames: List<XStackFrame>) {
for (stackFrame in stackFrames) {
cs.launch(Dispatchers.Default) {
stackFrame.customizePresentation().collectLatest { newPresentation ->
cache += stackFrame to newPresentation
cache += stackFrame.identityWrapper() to newPresentation
repaintRequests.emit(Unit)
withContext(Dispatchers.EDT) {
// TODO cooldown period to reduce invocations count
@@ -52,7 +53,7 @@ class XFramesAsyncPresentationHandler(private val framesList: XDebuggerFramesLis
fun clear(): Unit = cache.clear()
fun customizePresentation(stackFrame: XStackFrame, container: ColoredTextContainer) {
cache[stackFrame]?.customizePresentation(container)
cache[stackFrame.identityWrapper()]?.customizePresentation(container)
}
fun sessionStopped() {
@@ -11,6 +11,8 @@ import com.intellij.util.awaitCancellationAndInvoke
import com.intellij.xdebugger.frame.XStackFrame
import com.intellij.xdebugger.impl.XDebugSessionImpl
import com.intellij.xdebugger.impl.rpc.XStackFrameId
import com.intellij.xdebugger.impl.util.identityConcurrentHashMap
import com.intellij.xdebugger.impl.util.identityWrapper
import kotlinx.coroutines.CoroutineScope
import org.jetbrains.annotations.ApiStatus
import java.util.concurrent.ConcurrentHashMap
@@ -57,10 +59,10 @@ private class XStackFrameDeduplicator {
}
private class ScopeBoundStorage() {
private val storage = ConcurrentHashMap<IdentityWrapper, XStackFrameId>()
private val storage = identityConcurrentHashMap<XStackFrame, XStackFrameId>()
fun getOrStore(stack: XStackFrame, createId: () -> XStackFrameId): XStackFrameId {
return storage.computeIfAbsent(IdentityWrapper(stack)) { createId() }
return storage.computeIfAbsent(stack.identityWrapper()) { createId() }
}
fun clear() {
@@ -68,16 +70,6 @@ private class XStackFrameDeduplicator {
}
}
private class IdentityWrapper(val frame: XStackFrame) {
override fun equals(other: Any?): Boolean {
return other is IdentityWrapper && frame === other.frame
}
override fun hashCode(): Int {
return System.identityHashCode(frame)
}
}
companion object {
fun getInstance(): XStackFrameDeduplicator = service()
}
@@ -0,0 +1,17 @@
// 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.util
import fleet.multiplatform.shims.ConcurrentHashMap
internal class IdentityWrapper<T>(val obj: T) {
override fun equals(other: Any?): Boolean {
return other is IdentityWrapper<T> && obj === other.obj
}
override fun hashCode(): Int {
return System.identityHashCode(obj)
}
}
internal fun <K> K.identityWrapper() = IdentityWrapper(this)
internal fun <K, V> identityConcurrentHashMap() = ConcurrentHashMap<IdentityWrapper<K>, V>()