diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesAsyncPresentationManager.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesAsyncPresentationManager.kt index f5fa79a4c47b..3623c2287d97 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesAsyncPresentationManager.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesAsyncPresentationManager.kt @@ -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() + private val cache = identityConcurrentHashMap() private val repaintRequests = MutableSharedFlow() fun scheduleForFrames(stackFrames: List) { 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() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/models/XStackFrameModel.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/models/XStackFrameModel.kt index 0842f11a71f2..42ec227610f9 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/models/XStackFrameModel.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rpc/models/XStackFrameModel.kt @@ -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() + private val storage = identityConcurrentHashMap() 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() } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/util/IdentityConcurrentHashMap.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/util/IdentityConcurrentHashMap.kt new file mode 100644 index 000000000000..2a831d11ac6c --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/util/IdentityConcurrentHashMap.kt @@ -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(val obj: T) { + override fun equals(other: Any?): Boolean { + return other is IdentityWrapper && obj === other.obj + } + + override fun hashCode(): Int { + return System.identityHashCode(obj) + } +} + +internal fun K.identityWrapper() = IdentityWrapper(this) +internal fun identityConcurrentHashMap() = ConcurrentHashMap, V>()