From c688cef79c7c59bfbc3816103c32259e1d75f00a Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Wed, 28 Dec 2016 17:45:00 +0300 Subject: [PATCH 01/13] Do not store debug session on hard references in ClassesTable --- .../memory/action/ClassesActionBase.java | 10 ++----- .../memory/action/JumpToTypeSourceAction.java | 21 +++++++-------- .../ShowInstancesFromClassesViewAction.java | 14 +++++++--- .../memory/action/ShowNewInstancesAction.java | 27 +++++++++++-------- .../JumpToAllocationSourceAction.java | 26 +++++++++--------- .../tracking/TrackInstancesToggleAction.java | 24 +++++++---------- .../debugger/memory/ui/ClassesTable.java | 25 +++++++---------- 7 files changed, 70 insertions(+), 77 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/ClassesActionBase.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/ClassesActionBase.java index f9d148da405b..45be8c711db9 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/ClassesActionBase.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/ClassesActionBase.java @@ -15,13 +15,12 @@ */ package com.intellij.debugger.memory.action; +import com.intellij.debugger.memory.ui.ClassesTable; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; -import com.intellij.xdebugger.XDebugSession; import com.sun.jdi.ReferenceType; import org.jetbrains.annotations.Nullable; -import com.intellij.debugger.memory.ui.ClassesTable; public abstract class ClassesActionBase extends AnAction { @Override @@ -35,7 +34,7 @@ public abstract class ClassesActionBase extends AnAction { } protected boolean isEnabled(AnActionEvent e) { - Project project = e.getProject(); + final Project project = e.getProject(); return project != null && !project.isDisposed(); } @@ -45,9 +44,4 @@ public abstract class ClassesActionBase extends AnAction { protected ReferenceType getSelectedClass(AnActionEvent e) { return e.getData(ClassesTable.SELECTED_CLASS_KEY); } - - @Nullable - XDebugSession getDebugSession(AnActionEvent e) { - return e.getData(ClassesTable.DEBUG_SESSION_KEY); - } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/JumpToTypeSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/JumpToTypeSourceAction.java index ea4c30ecdcfb..f3a03b85373a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/JumpToTypeSourceAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/JumpToTypeSourceAction.java @@ -21,8 +21,9 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.xdebugger.XDebugSession; -import com.sun.jdi.*; +import com.sun.jdi.ArrayType; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.VirtualMachine; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,17 +48,15 @@ public class JumpToTypeSourceAction extends ClassesActionBase { @Nullable private PsiClass getPsiClass(AnActionEvent e) { - ReferenceType selectedClass = getSelectedClass(e); - XDebugSession session = getDebugSession(e); - if (selectedClass == null || session == null) { + final ReferenceType selectedClass = getSelectedClass(e); + final Project project = e.getProject(); + if (selectedClass == null || project == null) { return null; } - ReferenceType targetClass = getObjectType(selectedClass); + final ReferenceType targetClass = getObjectType(selectedClass); if (targetClass != null) { - Project project = session.getProject(); - return DebuggerUtils - .findClass(targetClass.name(), project, GlobalSearchScope.allScope(project)); + return DebuggerUtils.findClass(targetClass.name(), project, GlobalSearchScope.allScope(project)); } return null; @@ -69,8 +68,8 @@ public class JumpToTypeSourceAction extends ClassesActionBase { return ref; } - String elementTypeName = ref.name().replace("[]", ""); - VirtualMachine vm = ref.virtualMachine(); + final String elementTypeName = ref.name().replace("[]", ""); + final VirtualMachine vm = ref.virtualMachine(); final List referenceTypes = vm.classesByName(elementTypeName); if (referenceTypes.size() == 1) { return referenceTypes.get(0); diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowInstancesFromClassesViewAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowInstancesFromClassesViewAction.java index 35ccc88f2c11..c52b5d027bfa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowInstancesFromClassesViewAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowInstancesFromClassesViewAction.java @@ -16,13 +16,16 @@ package com.intellij.debugger.memory.action; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.Project; import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XDebuggerManager; import com.sun.jdi.ReferenceType; import com.intellij.debugger.memory.ui.ClassesTable; import com.intellij.debugger.memory.ui.InstancesWindow; public class ShowInstancesFromClassesViewAction extends ShowInstancesAction { private static final String POPUP_ELEMENT_LABEL = "Show Instances"; + @Override protected boolean isEnabled(AnActionEvent e) { return super.isEnabled(e) && getSelectedClass(e) != null; @@ -30,10 +33,13 @@ public class ShowInstancesFromClassesViewAction extends ShowInstancesAction { @Override protected void perform(AnActionEvent e) { - XDebugSession debugSession = getDebugSession(e); - ReferenceType selectedClass = getSelectedClass(e); - if (debugSession != null && selectedClass != null) { - new InstancesWindow(debugSession, selectedClass::instances, selectedClass.name()).show(); + final Project project = e.getProject(); + final ReferenceType selectedClass = getSelectedClass(e); + if (project != null && selectedClass != null) { + final XDebugSession debugSession = XDebuggerManager.getInstance(project).getCurrentSession(); + if (debugSession != null) { + new InstancesWindow(debugSession, limit -> selectedClass.instances(limit), selectedClass.name()).show(); + } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowNewInstancesAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowNewInstancesAction.java index bc3dc86e68c3..53fd0b7eef6f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowNewInstancesAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowNewInstancesAction.java @@ -15,22 +15,23 @@ */ package com.intellij.debugger.memory.action; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.xdebugger.XDebugSession; -import com.sun.jdi.ReferenceType; -import com.intellij.debugger.memory.utils.InstancesProvider; import com.intellij.debugger.memory.ui.ClassesTable; import com.intellij.debugger.memory.ui.InstancesWindow; +import com.intellij.debugger.memory.utils.InstancesProvider; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.Project; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XDebuggerManager; +import com.sun.jdi.ReferenceType; public class ShowNewInstancesAction extends ShowInstancesAction { private static final String POPUP_ELEMENT_LABEL = "Show New Instances"; @Override protected boolean isEnabled(AnActionEvent e) { - XDebugSession session = getDebugSession(e); - ReferenceType selectedClass = getSelectedClass(e); - InstancesProvider provider = e.getData(ClassesTable.NEW_INSTANCES_PROVIDER_KEY); - return super.isEnabled(e) && session != null && selectedClass != null && provider != null; + final ReferenceType selectedClass = getSelectedClass(e); + final InstancesProvider provider = e.getData(ClassesTable.NEW_INSTANCES_PROVIDER_KEY); + return super.isEnabled(e) && selectedClass != null && provider != null; } @Override @@ -51,9 +52,13 @@ public class ShowNewInstancesAction extends ShowInstancesAction { @Override protected void perform(AnActionEvent e) { - XDebugSession session = getDebugSession(e); - ReferenceType selectedClass = getSelectedClass(e); - InstancesProvider provider = e.getData(ClassesTable.NEW_INSTANCES_PROVIDER_KEY); + final Project project = e.getProject(); + + final ReferenceType selectedClass = getSelectedClass(e); + final InstancesProvider provider = e.getData(ClassesTable.NEW_INSTANCES_PROVIDER_KEY); + final XDebugSession session = project != null + ? XDebuggerManager.getInstance(project).getCurrentSession() + : null; if (selectedClass != null && provider != null && session != null) { new InstancesWindow(session, provider, selectedClass.name()).show(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java index fdbbc170ca28..a5147031cb5d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java @@ -41,13 +41,13 @@ public class JumpToAllocationSourceAction extends DebuggerTreeAction { @Override protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) { - Project project = e.getProject(); - List stack = getStack(e); - if(project != null && stack != null) { - XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); - if(session != null) { - GlobalSearchScope searchScope = DebuggerManager.getInstance(project) - .getDebugProcess(session.getDebugProcess().getProcessHandler()).getSearchScope(); + final Project project = e.getProject(); + final List stack = getStack(e); + if (project != null && stack != null) { + final XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); + if (session != null) { + final GlobalSearchScope searchScope = DebuggerManager.getInstance(project) + .getDebugProcess(session.getDebugProcess().getProcessHandler()).getSearchScope(); new StackFramePopup(project, stack, searchScope).show(); } } @@ -55,15 +55,15 @@ public class JumpToAllocationSourceAction extends DebuggerTreeAction { @Nullable private List getStack(AnActionEvent e) { - Project project = e.getProject(); - XValueNodeImpl selectedNode = getSelectedNode(e.getDataContext()); - ObjectReference ref = selectedNode != null ? getObjectReference(selectedNode) : null; - if(project == null || ref == null) { + final Project project = e.getProject(); + final XValueNodeImpl selectedNode = getSelectedNode(e.getDataContext()); + final ObjectReference ref = selectedNode != null ? getObjectReference(selectedNode) : null; + if (project == null || ref == null) { return null; } - XDebugSession session = e.getData(InstancesTree.DEBUG_SESSION_DATA_KEY); - CreationPositionTracker tracker = CreationPositionTracker.getInstance(project); + final XDebugSession session = e.getData(InstancesTree.DEBUG_SESSION_DATA_KEY); + final CreationPositionTracker tracker = CreationPositionTracker.getInstance(project); return session == null || tracker == null ? null : tracker.getStack(session, ref); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/TrackInstancesToggleAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/TrackInstancesToggleAction.java index c3131508ef49..0fc1f80bf86c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/TrackInstancesToggleAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/TrackInstancesToggleAction.java @@ -20,7 +20,7 @@ import com.intellij.debugger.memory.tracking.TrackingType; import com.intellij.debugger.memory.ui.ClassesTable; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.ToggleAction; -import com.intellij.xdebugger.XDebugSession; +import com.intellij.openapi.project.Project; import com.sun.jdi.ArrayType; import com.sun.jdi.ReferenceType; import org.jetbrains.annotations.NotNull; @@ -32,7 +32,8 @@ public class TrackInstancesToggleAction extends ToggleAction { ReferenceType selectedClass = getSelectedClass(e); if (selectedClass instanceof ArrayType) { e.getPresentation().setEnabled(false); - } else { + } + else { super.update(e); } } @@ -40,9 +41,9 @@ public class TrackInstancesToggleAction extends ToggleAction { @Override public boolean isSelected(AnActionEvent e) { ReferenceType selectedClass = getSelectedClass(e); - XDebugSession debugSession = getDebugSession(e); - if (debugSession != null && selectedClass != null) { - InstancesTracker tracker = InstancesTracker.getInstance(debugSession.getProject()); + final Project project = e.getProject(); + if (project != null && selectedClass != null) { + InstancesTracker tracker = InstancesTracker.getInstance(project); return tracker.isTracked(selectedClass.name()); } @@ -51,10 +52,10 @@ public class TrackInstancesToggleAction extends ToggleAction { @Override public void setSelected(AnActionEvent e, boolean state) { - ReferenceType selectedClass = getSelectedClass(e); - XDebugSession debugSession = getDebugSession(e); - if (selectedClass != null && debugSession != null) { - InstancesTracker tracker = InstancesTracker.getInstance(debugSession.getProject()); + final ReferenceType selectedClass = getSelectedClass(e); + final Project project = e.getProject(); + if (selectedClass != null && project != null) { + InstancesTracker tracker = InstancesTracker.getInstance(project); boolean isAlreadyTracked = tracker.isTracked(selectedClass.name()); if (isAlreadyTracked && !state) { @@ -71,9 +72,4 @@ public class TrackInstancesToggleAction extends ToggleAction { private static ReferenceType getSelectedClass(AnActionEvent e) { return e.getData(ClassesTable.SELECTED_CLASS_KEY); } - - @Nullable - private static XDebugSession getDebugSession(AnActionEvent e) { - return e.getData(ClassesTable.DEBUG_SESSION_KEY); - } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesTable.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesTable.java index 6c4bcb9cbb15..28d02623df65 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesTable.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesTable.java @@ -16,8 +16,11 @@ package com.intellij.debugger.memory.ui; import com.intellij.debugger.memory.component.InstancesTracker; +import com.intellij.debugger.memory.tracking.TrackerForNewInstances; +import com.intellij.debugger.memory.tracking.TrackingType; import com.intellij.debugger.memory.utils.AbstractTableColumnDescriptor; import com.intellij.debugger.memory.utils.AbstractTableModelWithColumns; +import com.intellij.debugger.memory.utils.InstancesProvider; import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataKey; @@ -39,9 +42,6 @@ import com.sun.jdi.ReferenceType; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.intellij.debugger.memory.tracking.TrackerForNewInstances; -import com.intellij.debugger.memory.tracking.TrackingType; -import com.intellij.debugger.memory.utils.InstancesProvider; import javax.swing.*; import javax.swing.border.Border; @@ -52,7 +52,6 @@ import java.util.concurrent.ConcurrentHashMap; public class ClassesTable extends JBTable implements DataProvider, Disposable { public static final DataKey SELECTED_CLASS_KEY = DataKey.create("ClassesTable.SelectedClass"); - public static final DataKey DEBUG_SESSION_KEY = DataKey.create("ClassesTable.DebugSession"); public static final DataKey NEW_INSTANCES_PROVIDER_KEY = DataKey.create("ClassesTable.NewInstances"); public static final DataKey REF_COUNT_PROVIDER_KEY = @@ -63,10 +62,9 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable { private static final int CLASSES_COLUMN_PREFERRED_WIDTH = 250; private static final int COUNT_COLUMN_MIN_WIDTH = 80; private static final int DIFF_COLUMN_MIN_WIDTH = 80; + private static final UnknownDiffValue UNKNOWN_VALUE = new UnknownDiffValue(); private final DiffViewTableModel myModel = new DiffViewTableModel(); - private final UnknownDiffValue myUnknownValue = new UnknownDiffValue(); - private final XDebugSession myDebugSession; private final Map myCounts = new ConcurrentHashMap<>(); private final InstancesTracker myInstancesTracker; private final ClassesFilteredView myParent; @@ -84,11 +82,10 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable { boolean onlyTracked, @NotNull ClassesFilteredView parent) { setModel(myModel); - myDebugSession = session; myOnlyWithDiff = onlyWithDiff; myOnlyWithInstances = onlyWithInstances; myOnlyTracked = onlyTracked; - myInstancesTracker = InstancesTracker.getInstance(myDebugSession.getProject()); + myInstancesTracker = InstancesTracker.getInstance(session.getProject()); myParent = parent; TableColumn classesColumn = getColumnModel().getColumn(DiffViewTableModel.CLASSNAME_COLUMN_INDEX); @@ -115,7 +112,7 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable { public boolean include(Entry entry) { int ix = entry.getIdentifier(); ReferenceType ref = myItems.get(ix); - DiffValue diff = myCounts.getOrDefault(ref, myUnknownValue); + DiffValue diff = myCounts.getOrDefault(ref, UNKNOWN_VALUE); boolean isFilteringOptionsRefused = myOnlyWithDiff && diff.diff() == 0 || myOnlyWithInstances && !diff.hasInstance() @@ -229,7 +226,7 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable { ReferenceType ref = classes.get(i); DiffValue oldValue = isInitialized && !myCounts.containsKey(ref) ? new DiffValue(0, 0) - : myCounts.getOrDefault(ref, myUnknownValue); + : myCounts.getOrDefault(ref, UNKNOWN_VALUE); myCounts.put(ref, oldValue.update(counts[i])); } @@ -252,16 +249,12 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable { myModel.show(); } - @Nullable @Override public Object getData(@NonNls String dataId) { if (SELECTED_CLASS_KEY.is(dataId)) { return getSelectedClass(); } - if (DEBUG_SESSION_KEY.is(dataId)) { - return myDebugSession; - } if (NEW_INSTANCES_PROVIDER_KEY.is(dataId)) { ReferenceType selectedClass = getSelectedClass(); if (selectedClass != null) { @@ -310,13 +303,13 @@ public class ClassesTable extends JBTable implements DataProvider, Disposable { new AbstractTableColumnDescriptor("Count", Long.class) { @Override public Object getValue(int ix) { - return myCounts.getOrDefault(myItems.get(ix), myUnknownValue).myCurrentCount; + return myCounts.getOrDefault(myItems.get(ix), UNKNOWN_VALUE).myCurrentCount; } }, new AbstractTableColumnDescriptor("Diff", DiffValue.class) { @Override public Object getValue(int ix) { - return myCounts.getOrDefault(myItems.get(ix), myUnknownValue); + return myCounts.getOrDefault(myItems.get(ix), UNKNOWN_VALUE); } } }); From 2ff22268bd97dc198fa9d1431750bbd835940f30 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Wed, 28 Dec 2016 17:48:07 +0300 Subject: [PATCH 02/13] Fix typos and spacing, add notnull annotation, simplify map.get calls --- .../component/CreationPositionTracker.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/component/CreationPositionTracker.java b/java/debugger/impl/src/com/intellij/debugger/memory/component/CreationPositionTracker.java index e49668f18a7a..ca8c6a9a2f87 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/component/CreationPositionTracker.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/component/CreationPositionTracker.java @@ -36,12 +36,12 @@ public class CreationPositionTracker extends AbstractProjectComponent { * Stores all tracked instance for each debug session. */ private final ConcurrentHashMap>> - mySession2Reference2Stack = new ConcurrentHashMap<>(); + mySession2Reference2Stack = new ConcurrentHashMap<>(); private final ConcurrentHashMap>> - myPinnedSession2Reference2Stack = new ConcurrentHashMap<>(); + myPinnedSession2Reference2Stack = new ConcurrentHashMap<>(); - public CreationPositionTracker(Project project) { + public CreationPositionTracker(@NotNull Project project) { super(project); } @@ -52,7 +52,7 @@ public class CreationPositionTracker extends AbstractProjectComponent { @Nullable public List getStack(@NotNull XDebugSession session, @NotNull ObjectReference ref) { - List stack = extract(mySession2Reference2Stack, session, ref); + final List stack = extract(mySession2Reference2Stack, session, ref); return stack != null ? stack : extract(myPinnedSession2Reference2Stack, session, ref); } @@ -72,17 +72,17 @@ public class CreationPositionTracker extends AbstractProjectComponent { } public void releaseBySession(@NotNull XDebugSession session) { - if(mySession2Reference2Stack.containsKey(session)) { + if (mySession2Reference2Stack.containsKey(session)) { mySession2Reference2Stack.put(session, new ConcurrentHashMap<>()); } } public void unpinStacks(@NotNull XDebugSession session, @NotNull ReferenceType ref) { - Map> ref2Stack = myPinnedSession2Reference2Stack.getOrDefault(session, null); + final Map> ref2Stack = myPinnedSession2Reference2Stack.get(session); if (ref2Stack != null) { - Iterator iterator = ref2Stack.keySet().iterator(); + final Iterator iterator = ref2Stack.keySet().iterator(); while (iterator.hasNext()) { - ObjectReference reference = iterator.next(); + final ObjectReference reference = iterator.next(); if (ref.equals(reference.referenceType())) { iterator.remove(); } @@ -95,21 +95,21 @@ public class CreationPositionTracker extends AbstractProjectComponent { } public void pinStacks(@NotNull XDebugSession session, @NotNull ReferenceType ref) { - Map> ref2Stack = mySession2Reference2Stack.getOrDefault(session, null); + final Map> ref2Stack = mySession2Reference2Stack.get(session); if (ref2Stack != null) { - Map> ref2StacksByReferenceType = ref2Stack.entrySet().stream() - .filter(entry -> ref.equals(entry.getKey().referenceType())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + final Map> ref2StacksByReferenceType = ref2Stack.entrySet().stream() + .filter(entry -> ref.equals(entry.getKey().referenceType())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); myPinnedSession2Reference2Stack.put(session, ref2StacksByReferenceType); } } @Nullable - private static T extract(@NotNull Map> map, - @NotNull XDebugSession session, @NotNull ObjectReference ref) { - Map ref2something = map.getOrDefault(session, null); - if(ref2something != null) { - return ref2something.getOrDefault(ref, null); + private static T extract(@NotNull Map> map, + @NotNull XDebugSession session, @NotNull ObjectReference ref) { + final Map ref2something = map.get(session); + if (ref2something != null) { + return ref2something.get(ref); } return null; From 04663933593ac88a8aa974a0994fa6fbef953757 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Wed, 28 Dec 2016 18:54:39 +0300 Subject: [PATCH 03/13] Do not hold XDebugSession in InstancesTree and InstancesWindow --- .../JumpToAllocationSourceAction.java | 9 ++- .../debugger/memory/ui/InstancesTree.java | 28 ++------ .../debugger/memory/ui/InstancesWindow.java | 64 ++++++++++--------- 3 files changed, 44 insertions(+), 57 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java index a5147031cb5d..c08a619a3d78 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java @@ -17,7 +17,9 @@ package com.intellij.debugger.memory.action.tracking; import com.intellij.debugger.DebuggerManager; import com.intellij.debugger.memory.action.DebuggerTreeAction; +import com.intellij.debugger.memory.component.CreationPositionTracker; import com.intellij.debugger.memory.ui.StackFramePopup; +import com.intellij.debugger.memory.utils.StackFrameItem; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; import com.intellij.psi.search.GlobalSearchScope; @@ -27,9 +29,6 @@ import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import com.sun.jdi.ObjectReference; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.intellij.debugger.memory.component.CreationPositionTracker; -import com.intellij.debugger.memory.utils.StackFrameItem; -import com.intellij.debugger.memory.ui.InstancesTree; import java.util.List; @@ -62,8 +61,8 @@ public class JumpToAllocationSourceAction extends DebuggerTreeAction { return null; } - final XDebugSession session = e.getData(InstancesTree.DEBUG_SESSION_DATA_KEY); + final XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); final CreationPositionTracker tracker = CreationPositionTracker.getInstance(project); - return session == null || tracker == null ? null : tracker.getStack(session, ref); + return session != null && tracker != null ? tracker.getStack(session, ref) : null; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesTree.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesTree.java index 8bd1c851482c..c6c33e7ce2b6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesTree.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesTree.java @@ -18,10 +18,8 @@ package com.intellij.debugger.memory.ui; import com.intellij.debugger.ui.impl.watch.NodeDescriptorProvider; import com.intellij.debugger.ui.tree.NodeDescriptor; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.project.Project; import com.intellij.ui.SimpleTextAttributes; -import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.frame.*; import com.intellij.xdebugger.impl.actions.XDebuggerActions; @@ -32,7 +30,6 @@ import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeState; import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl; import com.sun.jdi.ObjectReference; import com.sun.jdi.Value; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,21 +38,17 @@ import java.util.ArrayList; import java.util.List; public class InstancesTree extends XDebuggerTree { - public static final DataKey DEBUG_SESSION_DATA_KEY = DataKey.create("InstancesTree.DebugSession"); private final XValueNodeImpl myRoot; private final Runnable myOnRootExpandAction; - private final XDebugSession myDebugSession; private List myChildren; InstancesTree(@NotNull Project project, - @NotNull XDebugSession debugSession, @NotNull XDebuggerEditorsProvider editorsProvider, @Nullable XValueMarkers valueMarkers, @NotNull Runnable onRootExpand) { super(project, editorsProvider, null, XDebuggerActions.INSPECT_TREE_POPUP_GROUP, valueMarkers); myOnRootExpandAction = onRootExpand; myRoot = new XValueNodeImpl(this, null, "root", new MyRootValue()); - myDebugSession = debugSession; myRoot.children(); setRoot(myRoot, false); @@ -96,16 +89,16 @@ public class InstancesTree extends XDebuggerTree { TreePath selectionPath = getSelectionPath(); Object selectedItem = selectionPath != null ? selectionPath.getLastPathComponent() : null; if (selectedItem instanceof XValueNodeImpl) { - XValueNodeImpl xValueNode = (XValueNodeImpl) selectedItem; + XValueNodeImpl xValueNode = (XValueNodeImpl)selectedItem; XValue valueContainer = xValueNode.getValueContainer(); if (valueContainer instanceof NodeDescriptorProvider) { - NodeDescriptor descriptor = ((NodeDescriptorProvider) valueContainer).getDescriptor(); + NodeDescriptor descriptor = ((NodeDescriptorProvider)valueContainer).getDescriptor(); if (descriptor instanceof ValueDescriptor) { - Value value = ((ValueDescriptor) descriptor).getValue(); + Value value = ((ValueDescriptor)descriptor).getValue(); - if (value instanceof ObjectReference) return (ObjectReference) value; + if (value instanceof ObjectReference) return (ObjectReference)value; } } } @@ -113,16 +106,6 @@ public class InstancesTree extends XDebuggerTree { return null; } - @Nullable - @Override - public Object getData(@NonNls String dataId) { - if (DEBUG_SESSION_DATA_KEY.is(dataId)) { - return myDebugSession; - } - - return super.getData(dataId); - } - enum RebuildPolicy { RELOAD_INSTANCES, ONLY_UPDATE_LABELS } @@ -132,7 +115,8 @@ public class InstancesTree extends XDebuggerTree { public void computeChildren(@NotNull XCompositeNode node) { if (myChildren == null) { myOnRootExpandAction.run(); - } else { + } + else { for (XValueChildrenList children : myChildren) { myRoot.addChildren(children, false); } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java index d9b0c548c413..93734dcf9b87 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java @@ -84,7 +84,7 @@ public class InstancesWindow extends DialogWrapper { private static final int DEFAULT_INSTANCES_LIMIT = 500000; private final Project myProject; - private final XDebugSession myDebugSession; + private final DebugProcessImpl myDebugProcess; private final InstancesProvider myInstancesProvider; private final String myClassName; private MyInstancesView myInstancesView; @@ -95,19 +95,25 @@ public class InstancesWindow extends DialogWrapper { super(session.getProject(), false); myProject = session.getProject(); - myDebugSession = session; + myDebugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject) + .getDebugProcess(session.getDebugProcess().getProcessHandler()); myInstancesProvider = provider; myClassName = className; addWarningMessage(null); - myDebugSession.addSessionListener(new XDebugSessionListener() { + session.addSessionListener(new XDebugSessionListener() { @Override public void sessionStopped() { ApplicationManager.getApplication().invokeLater(() -> close(OK_EXIT_CODE)); } }, myDisposable); setModal(false); + myInstancesView = new MyInstancesView(session); + myInstancesView.setPreferredSize( + new JBDimension(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT)); + init(); + JRootPane root = myInstancesView.getRootPane(); root.setDefaultButton(myInstancesView.myFilterButton); } @@ -126,9 +132,6 @@ public class InstancesWindow extends DialogWrapper { @Nullable @Override protected JComponent createCenterPanel() { - myInstancesView = new MyInstancesView(); - myInstancesView.setPreferredSize( - new JBDimension(DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT)); return myInstancesView; } @@ -165,20 +168,22 @@ public class InstancesWindow extends DialogWrapper { private final JButton myFilterButton = new JButton("Filter"); private final FilteringProgressView myProgress = new FilteringProgressView(); - private final AnActionListener.Adapter myActionListener = new MyActionListener(); private final Object myFilteringTaskLock = new Object(); private boolean myIsAndroidVM = false; private volatile MyFilteringWorker myFilteringTask = null; - MyInstancesView() { + MyInstancesView(@NotNull XDebugSession session) { super(new BorderLayout(0, JBUI.scale(BORDER_LAYOUT_DEFAULT_GAP))); Disposer.register(InstancesWindow.this.myDisposable, this); - XValueMarkers markers = getValueMarkers(); - ActionManager.getInstance().addAnActionListener(myActionListener, InstancesWindow.this.myDisposable); - myDebugSession.addSessionListener(myDebugSessionListener, InstancesWindow.this.myDisposable); + XValueMarkers markers = getValueMarkers(session); + if (markers != null) { + final MyActionListener listener = new MyActionListener(markers); + ActionManager.getInstance().addAnActionListener(listener, InstancesWindow.this.myDisposable); + } + session.addSessionListener(myDebugSessionListener, InstancesWindow.this.myDisposable); JavaDebuggerEditorsProvider editorsProvider = new JavaDebuggerEditorsProvider(); myFilterConditionEditor = new ExpressionEditorWithHistory(myProject, myClassName, @@ -203,7 +208,7 @@ public class InstancesWindow extends DialogWrapper { myProgress.addStopActionListener(this::cancelFilteringTask); - myInstancesTree = new InstancesTree(myProject, myDebugSession, editorsProvider, markers, this::updateInstances); + myInstancesTree = new InstancesTree(myProject, editorsProvider, markers, this::updateInstances); myFilterButton.addActionListener(e -> { String expression = myFilterConditionEditor.getExpression().getExpression(); @@ -229,7 +234,7 @@ public class InstancesWindow extends DialogWrapper { } }.installOn(list); - InstancesWithStackFrameView instancesWithStackFrame = new InstancesWithStackFrameView(myDebugSession, + InstancesWithStackFrameView instancesWithStackFrame = new InstancesWithStackFrameView(session, myInstancesTree, list, myClassName); add(filteringPane, BorderLayout.NORTH); @@ -248,12 +253,9 @@ public class InstancesWindow extends DialogWrapper { } private void updateInstances() { - DebugProcessImpl debugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject) - .getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler()); - cancelFilteringTask(); - debugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(debugProcess.getDebuggerContext()) { + myDebugProcess.getManagerThread().schedule(new DebuggerContextCommandImpl(myDebugProcess.getDebuggerContext()) { @Override public Priority getPriority() { return Priority.LOWEST; @@ -261,13 +263,13 @@ public class InstancesWindow extends DialogWrapper { @Override public void threadAction(@NotNull SuspendContextImpl suspendContext) { - myIsAndroidVM = AndroidUtil.isAndroidVM(debugProcess.getVirtualMachineProxy().getVirtualMachine()); + myIsAndroidVM = AndroidUtil.isAndroidVM(myDebugProcess.getVirtualMachineProxy().getVirtualMachine()); int limit = myIsAndroidVM ? AndroidUtil.ANDROID_INSTANCES_LIMIT : DEFAULT_INSTANCES_LIMIT; List instances = myInstancesProvider.getInstances(limit + 1); - EvaluationContextImpl evaluationContext = debugProcess + EvaluationContextImpl evaluationContext = myDebugProcess .getDebuggerContext().createEvaluationContext(); if (instances.size() > limit) { @@ -296,9 +298,9 @@ public class InstancesWindow extends DialogWrapper { } } - private XValueMarkers getValueMarkers() { - return myDebugSession instanceof XDebugSessionImpl - ? ((XDebugSessionImpl)myDebugSession).getValueMarkers() + private XValueMarkers getValueMarkers(@NotNull XDebugSession session) { + return session instanceof XDebugSessionImpl + ? ((XDebugSessionImpl)session).getValueMarkers() : null; } @@ -326,15 +328,19 @@ public class InstancesWindow extends DialogWrapper { } private class MyActionListener extends AnActionListener.Adapter { + private final XValueMarkers myValueMarkers; + + private MyActionListener(@NotNull XValueMarkers markers) { + myValueMarkers = markers; + } + @Override public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { if (dataContext.getData(PlatformDataKeys.CONTEXT_COMPONENT) == myInstancesView.myInstancesTree && (isAddToWatchesAction(action) || isEvaluateExpressionAction(action))) { final XValueNodeImpl selectedNode = XDebuggerTreeActionBase.getSelectedNode(dataContext); - final XValueMarkers markers = getValueMarkers(); - - if (markers != null && selectedNode != null) { + if (selectedNode != null) { TreeNode currentNode = selectedNode; while (!myInstancesTree.getRoot().equals(currentNode.getParent())) { currentNode = currentNode.getParent(); @@ -344,8 +350,8 @@ public class InstancesWindow extends DialogWrapper { final String expression = valueContainer.getEvaluationExpression(); if (expression != null) { - markers.markValue(valueContainer, - new ValueMarkup(expression.replace("@", ""), new JBColor(0, 0), null)); + myValueMarkers.markValue(valueContainer, + new ValueMarkup(expression.replace("@", ""), new JBColor(0, 0), null)); } ApplicationManager.getApplication().invokeLater(() -> myInstancesTree @@ -481,9 +487,7 @@ public class InstancesWindow extends DialogWrapper { @NotNull XExpression expression, @NotNull EvaluationContextImpl evaluationContext) { if (refs.size() != 0) { - DebugProcessImpl debugProcess = - (DebugProcessImpl)DebuggerManager.getInstance(myProject).getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler()); - myTask = new FilteringTask(refs.get(0).referenceType(), debugProcess, expression, refs, + myTask = new FilteringTask(refs.get(0).referenceType(), myDebugProcess, expression, refs, new MyFilteringCallback(evaluationContext)); } else { From a7a97ee004eed574967fc5ad2cb33f06d90354e9 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Wed, 28 Dec 2016 19:21:12 +0300 Subject: [PATCH 04/13] Do not hold debug session in ClassPreparedListener --- .../tracking/ClassPreparedListener.java | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ClassPreparedListener.java b/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ClassPreparedListener.java index 411e86e51d95..b591fdc4ff19 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ClassPreparedListener.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ClassPreparedListener.java @@ -19,24 +19,20 @@ import com.intellij.debugger.DebuggerManager; import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.requests.ClassPrepareRequestor; -import com.intellij.openapi.project.Project; import com.intellij.xdebugger.XDebugSession; import com.sun.jdi.ReferenceType; import com.sun.jdi.request.ClassPrepareRequest; import org.jetbrains.annotations.NotNull; public abstract class ClassPreparedListener { - private final XDebugSession myDebugSession; - private final Project myProject; protected ClassPreparedListener(@NotNull String className, @NotNull XDebugSession debugSession) { - myProject = debugSession.getProject(); - myDebugSession = debugSession; - DebugProcessImpl debugProcess = getDebugProcess(); - ClassPrepareRequestor request = new MyClassPreparedRequest(); - ClassPrepareRequest classPrepareRequest = debugProcess.getRequestsManager() - .createClassPrepareRequest(request, className); + final DebugProcessImpl debugProcess = (DebugProcessImpl)DebuggerManager.getInstance(debugSession.getProject()) + .getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); + final ClassPrepareRequestor request = new MyClassPreparedRequest(); + final ClassPrepareRequest classPrepareRequest = debugProcess.getRequestsManager() + .createClassPrepareRequest(request, className); if (classPrepareRequest != null) { classPrepareRequest.enable(); } @@ -44,16 +40,13 @@ public abstract class ClassPreparedListener { public abstract void onClassPrepared(@NotNull ReferenceType referenceType); - private DebugProcessImpl getDebugProcess() { - return (DebugProcessImpl) DebuggerManager.getInstance(myProject) - .getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler()); - } - private final class MyClassPreparedRequest implements ClassPrepareRequestor { @Override public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) { - getDebugProcess().getRequestsManager().deleteRequest(this); - onClassPrepared(referenceType); + if (debuggerProcess instanceof DebugProcessImpl) { + ((DebugProcessImpl)debuggerProcess).getRequestsManager().deleteRequest(this); + onClassPrepared(referenceType); + } } } } From eb1239d6cd6ea9eb1f580dee7962d837e181e5bd Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Wed, 28 Dec 2016 19:47:48 +0300 Subject: [PATCH 05/13] Fix typos/spacing --- .../memory/ui/ClassesFilteredView.java | 119 +++++++++--------- 1 file changed, 60 insertions(+), 59 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java index f25d6b714405..2cde6e9acf1b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java @@ -20,7 +20,17 @@ import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.engine.events.DebuggerCommandImpl; +import com.intellij.debugger.memory.component.CreationPositionTracker; +import com.intellij.debugger.memory.component.InstancesTracker; +import com.intellij.debugger.memory.component.MemoryViewManager; +import com.intellij.debugger.memory.component.MemoryViewManagerState; +import com.intellij.debugger.memory.event.InstancesTrackerListener; import com.intellij.debugger.memory.event.MemoryViewManagerListener; +import com.intellij.debugger.memory.tracking.ClassPreparedListener; +import com.intellij.debugger.memory.tracking.ConstructorInstancesTracker; +import com.intellij.debugger.memory.tracking.TrackerForNewInstances; +import com.intellij.debugger.memory.tracking.TrackingType; +import com.intellij.debugger.memory.utils.AndroidUtil; import com.intellij.debugger.memory.utils.KeyboardUtils; import com.intellij.debugger.memory.utils.LowestPriorityCommand; import com.intellij.debugger.memory.utils.SingleAlarmWithMutableDelay; @@ -42,16 +52,6 @@ import com.sun.jdi.ReferenceType; import com.sun.jdi.VirtualMachine; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.intellij.debugger.memory.component.CreationPositionTracker; -import com.intellij.debugger.memory.component.InstancesTracker; -import com.intellij.debugger.memory.component.MemoryViewManager; -import com.intellij.debugger.memory.component.MemoryViewManagerState; -import com.intellij.debugger.memory.event.InstancesTrackerListener; -import com.intellij.debugger.memory.tracking.ClassPreparedListener; -import com.intellij.debugger.memory.tracking.ConstructorInstancesTracker; -import com.intellij.debugger.memory.tracking.TrackerForNewInstances; -import com.intellij.debugger.memory.tracking.TrackingType; -import com.intellij.debugger.memory.utils.AndroidUtil; import javax.swing.FocusManager; import javax.swing.*; @@ -107,26 +107,26 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable myProject = debugSession.getProject(); myDebugSession = debugSession; - myDebugProcess = (DebugProcessImpl) DebuggerManager.getInstance(myProject) - .getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler()); + myDebugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject) + .getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler()); if (myDebugProcess == null) { throw new NullPointerException("Failed to receive a java debug process"); } myInstancesTracker = InstancesTracker.getInstance(myProject); - InstancesTrackerListener instancesTrackerListener = new InstancesTrackerListener() { + final InstancesTrackerListener instancesTrackerListener = new InstancesTrackerListener() { @Override public void classChanged(@NotNull String name, @NotNull TrackingType type) { ReferenceType ref = myTable.getClassByName(name); if (ref != null) { myDebugProcess.getManagerThread() - .schedule(new LowestPriorityCommand(getSuspendContext()) { - @Override - public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception { - trackClass(ref, type, myIsTrackersActivated); - } - }); + .schedule(new LowestPriorityCommand(getSuspendContext()) { + @Override + public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception { + trackClass(ref, type, myIsTrackersActivated); + } + }); } myTable.repaint(); } @@ -161,7 +161,8 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable trackClass(referenceType, type, myIsTrackersActivated); } }; - } else { + } + else { for (ReferenceType ref : classes) { trackClass(ref, type, myIsTrackersActivated); } @@ -172,10 +173,10 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable } }); - MemoryViewManagerState memoryViewManagerState = MemoryViewManager.getInstance().getState(); + final MemoryViewManagerState memoryViewManagerState = MemoryViewManager.getInstance().getState(); myTable = new ClassesTable(myDebugSession, memoryViewManagerState.isShowWithDiffOnly, - memoryViewManagerState.isShowWithInstancesOnly, memoryViewManagerState.isShowTrackedOnly, this); + memoryViewManagerState.isShowWithInstancesOnly, memoryViewManagerState.isShowTrackedOnly, this); myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_RUNNING); Disposer.register(this, myTable); @@ -186,14 +187,15 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable myTable.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { - int keyCode = e.getKeyCode(); + final int keyCode = e.getKeyCode(); if (KeyboardUtils.isEnterKey(keyCode)) { handleClassSelection(myTable.getSelectedClass()); - } else if (KeyboardUtils.isCharacter(keyCode) || KeyboardUtils.isBackSpace(keyCode)) { - String text = myFilterTextField.getText(); - String newText = KeyboardUtils.isBackSpace(keyCode) - ? text.substring(0, text.length() - 1) - : text + e.getKeyChar(); + } + else if (KeyboardUtils.isCharacter(keyCode) || KeyboardUtils.isBackSpace(keyCode)) { + final String text = myFilterTextField.getText(); + final String newText = KeyboardUtils.isBackSpace(keyCode) + ? text.substring(0, text.length() - 1) + : text + e.getKeyChar(); myFilterTextField.setText(newText); FocusManager.getCurrentManager().focusNextComponent(myFilterTextField); } @@ -244,11 +246,6 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable mySingleAlarm.cancelAllRequests(); } - @Override - public void sessionStopped() { - debugSession.removeSessionListener(this); - } - @Override public void sessionPaused() { ApplicationManager.getApplication().invokeLater(() -> myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_SUSPENDED)); @@ -261,7 +258,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable if (myLastSuspendContext != null) { ApplicationManager.getApplication().invokeLater(() -> myTable.setBusy(true)); myDebugProcess.getManagerThread() - .schedule(new MyUpdateClassesCommand(myLastSuspendContext)); + .schedule(new MyUpdateClassesCommand(myLastSuspendContext)); } }, this); @@ -275,7 +272,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable } }); - JScrollPane scroll = ScrollPaneFactory.createScrollPane(myTable, SideBorder.TOP); + final JScrollPane scroll = ScrollPaneFactory.createScrollPane(myTable, SideBorder.TOP); addToTop(myFilterTextField); addToCenter(scroll); } @@ -290,16 +287,17 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable boolean isTrackerEnabled) { LOG.assertTrue(DebuggerManager.getInstance(myProject).isDebuggerManagerThread()); if (type == TrackingType.CREATION) { - ConstructorInstancesTracker old = myConstructorTrackedClasses.getOrDefault(ref, null); + final ConstructorInstancesTracker old = myConstructorTrackedClasses.getOrDefault(ref, null); if (old != null) { Disposer.dispose(old); } - ConstructorInstancesTracker tracker = new ConstructorInstancesTracker(ref, myDebugSession); + final ConstructorInstancesTracker tracker = new ConstructorInstancesTracker(ref, myDebugSession); tracker.setBackgroundMode(!myIsActive); if (isTrackerEnabled) { tracker.enable(); - } else { + } + else { tracker.disable(); } @@ -310,7 +308,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable private void handleClassSelection(@Nullable ReferenceType ref) { if (ref != null && myDebugSession.isSuspended()) { - new InstancesWindow(myDebugSession, ref::instances, ref.name()).show(); + new InstancesWindow(myDebugSession, limit -> ref.instances(limit), ref.name()).show(); } } @@ -329,7 +327,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable } private static ActionPopupMenu createContextMenu() { - ActionGroup group = (ActionGroup) ActionManager.getInstance().getAction("MemoryView.ClassesPopupActionGroup"); + final ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction("MemoryView.ClassesPopupActionGroup"); return ActionManager.getInstance().createActionPopupMenu("MemoryView.ClassesPopupActionGroup", group); } @@ -348,7 +346,8 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable protected void action() throws Exception { if (active) { doActivate(); - } else { + } + else { doPause(); } } @@ -380,7 +379,8 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable if (!myIsTrackersActivated) { myConstructorTrackedClasses.values().forEach(ConstructorInstancesTracker::enable); myIsTrackersActivated = true; - } else { + } + else { commitAllTrackers(); } final List classes = myDebugProcess.getVirtualMachineProxy().allClasses(); @@ -389,33 +389,33 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable return; } - VirtualMachine vm = classes.get(0).virtualMachine(); - int batchSize = AndroidUtil.isAndroidVM(vm) - ? AndroidUtil.ANDROID_COUNT_BY_CLASSES_BATCH_SIZE - : DEFAULT_BATCH_SIZE; + final VirtualMachine vm = classes.get(0).virtualMachine(); + final int batchSize = AndroidUtil.isAndroidVM(vm) + ? AndroidUtil.ANDROID_COUNT_BY_CLASSES_BATCH_SIZE + : DEFAULT_BATCH_SIZE; - List chunks = new SmartList<>(); - int size = classes.size(); + final List chunks = new SmartList<>(); + final int size = classes.size(); for (int begin = 0, end = Math.min(batchSize, size); begin != size && isContextValid(); begin = end, end = Math.min(end + batchSize, size)) { - List batch = classes.subList(begin, end); + final List batch = classes.subList(begin, end); - long start = System.nanoTime(); - long[] counts = vm.instanceCounts(batch); - long delay = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); + final long start = System.nanoTime(); + final long[] counts = vm.instanceCounts(batch); + final long delay = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); chunks.add(counts); - int waitTime = (int) Math.min(DELAY_BEFORE_INSTANCES_QUERY_COEFFICIENT * delay, MAX_DELAY_MILLIS); + final int waitTime = (int)Math.min(DELAY_BEFORE_INSTANCES_QUERY_COEFFICIENT * delay, MAX_DELAY_MILLIS); mySingleAlarm.setDelay(waitTime); LOG.info(String.format("Instances query time = %d ms. Count = %d", delay, batch.size())); } if (isContextValid()) { final long[] counts = chunks.size() == 1 ? chunks.get(0) : IntStream.range(0, chunks.size()).boxed() - .flatMapToLong(integer -> Arrays.stream(chunks.get(integer))) - .toArray(); + .flatMapToLong(integer -> Arrays.stream(chunks.get(integer))) + .toArray(); ApplicationManager.getApplication().invokeLater(() -> myTable.setClassesAndUpdateCounts(classes, counts)); } @@ -450,8 +450,8 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable } final CreationPositionTracker tracker = CreationPositionTracker.getInstance(myDebugSession.getProject()); - ReferenceType ref = myTable.getSelectedClass(); - TrackerForNewInstances strategy = ref == null ? null : getStrategy(ref); + final ReferenceType ref = myTable.getSelectedClass(); + final TrackerForNewInstances strategy = ref == null ? null : getStrategy(ref); if (strategy != null && tracker != null) { List newInstances = strategy.getNewInstances(); tracker.pinStacks(myDebugSession, ref); @@ -483,7 +483,8 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable public void mouseMoved(MouseEvent e) { if (isShowNewInstancesEvent(e)) { myTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } else { + } + else { myTable.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } @@ -498,7 +499,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable final int modelRow = myTable.convertRowIndexToModel(row); - final ReferenceType ref = (ReferenceType) myTable.getModel().getValueAt(modelRow, CLASSNAME_COLUMN_INDEX); + final ReferenceType ref = (ReferenceType)myTable.getModel().getValueAt(modelRow, CLASSNAME_COLUMN_INDEX); final ConstructorInstancesTracker tracker = myConstructorTrackedClasses.getOrDefault(ref, null); return tracker != null && tracker.isReady() && tracker.getCount() > 0; From f4b9ae37f514dba71021f9f40895642155bf1977 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Fri, 30 Dec 2016 17:22:38 +0300 Subject: [PATCH 06/13] Avoid storing debug sessions in MemoryViewToolWindowFactory --- .../component/MemoryViewDebugProcessData.java | 51 +++++++++ .../MemoryViewToolWindowFactory.java | 108 +++++++++--------- 2 files changed, 108 insertions(+), 51 deletions(-) create mode 100644 java/debugger/impl/src/com/intellij/debugger/memory/component/MemoryViewDebugProcessData.java diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/component/MemoryViewDebugProcessData.java b/java/debugger/impl/src/com/intellij/debugger/memory/component/MemoryViewDebugProcessData.java new file mode 100644 index 000000000000..a378a66ab891 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/memory/component/MemoryViewDebugProcessData.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.memory.component; + +import com.intellij.debugger.memory.ui.ClassesFilteredView; +import com.intellij.debugger.memory.utils.StackFrameItem; +import com.intellij.openapi.util.Key; +import com.sun.jdi.ObjectReference; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Vitaliy.Bibaev + */ +public class MemoryViewDebugProcessData { + public static final Key KEY = Key.create("MemoryView.DebugProcessData"); + + private final ClassesFilteredView myClassesFilteredView; + private final Map> myTrackedFrames = new ConcurrentHashMap<>(); + + public MemoryViewDebugProcessData(@NotNull ClassesFilteredView classesView) { + myClassesFilteredView = classesView; + } + + @Nullable + List getStackFrames(@NotNull ObjectReference reference) { + return myTrackedFrames.get(reference); + } + + @NotNull + public ClassesFilteredView getClassesFilteredView() { + return myClassesFilteredView; + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java b/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java index d760f28bbe37..f614b1caa51e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java @@ -15,6 +15,11 @@ */ package com.intellij.debugger.memory.toolwindow; +import com.intellij.debugger.DebuggerManager; +import com.intellij.debugger.engine.DebugProcess; +import com.intellij.debugger.engine.DebugProcessImpl; +import com.intellij.debugger.engine.JavaDebugProcess; +import com.intellij.debugger.memory.component.MemoryViewDebugProcessData; import com.intellij.debugger.memory.component.MemoryViewManager; import com.intellij.debugger.memory.ui.ClassesFilteredView; import com.intellij.execution.Executor; @@ -35,6 +40,7 @@ import com.intellij.openapi.wm.ex.ToolWindowEx; import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; import com.intellij.openapi.wm.impl.ToolWindowImpl; import com.intellij.ui.components.JBLabel; +import com.intellij.util.EventDispatcher; import com.intellij.util.messages.MessageBusConnection; import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugSession; @@ -46,8 +52,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.util.Arrays; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.EventListener; public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware { private static final Logger LOG = Logger.getInstance(ClassesFilteredView.class); @@ -56,10 +61,9 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware private final JComponent myEmptyContent; private final JComponent myMemoryViewNotSupportedContent; - private final Map myMemoryViews = new ConcurrentHashMap<>(); + private final EventDispatcher myDispatcher = EventDispatcher.create(ToolWindowStateListener.class); - @Nullable - private ClassesFilteredView myCurrentView = null; + private volatile boolean myIsToolWindowVisible; { myEmptyContent = new JBLabel("Run debugging to see loaded classes", SwingConstants.CENTER); @@ -87,9 +91,11 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware .addToolWindowManagerListener(new ToolWindowManagerAdapter() { @Override public void stateChanged() { - if (!myMemoryViews.isEmpty() && !toolWindow.isDisposed()) { - myMemoryViews.values().forEach(classesFilteredView -> - classesFilteredView.setActive(toolWindow.isVisible())); + final boolean isVisible = toolWindow.isVisible(); + + if (isVisible != myIsToolWindowVisible) { + myDispatcher.getMulticaster().visibilityChanged(isVisible); + myIsToolWindowVisible ^= myIsToolWindowVisible; } } }, project); @@ -100,58 +106,50 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware toolWindow.getComponent().setLayout(new BorderLayout()); for (XDebugSession session : XDebuggerManager.getInstance(project).getDebugSessions()) { - addNewSession(session); + registerMemoryView(session); } updateCurrentMemoryView(project, toolWindow); } - private void addNewSession(@NotNull XDebugSession session) { + private void registerMemoryView(@NotNull XDebugSession session) { LOG.assertTrue(SwingUtilities.isEventDispatchThread()); - ToolWindow toolWindow = getToolWindow(session.getProject()); - if (!myMemoryViews.containsKey(session)) { - try { - ClassesFilteredView newView = new ClassesFilteredView(session); - newView.setActive(toolWindow != null && toolWindow.isVisible()); - myMemoryViews.put(session, newView); - } - catch (Throwable e) { - LOG.warn("Cannot create new instance of the memory view. " + e.getMessage()); - } - } - } + final XDebugProcess debugProcess = session.getDebugProcess(); + final Project project = session.getProject(); + final DebugProcess javaProcess = + DebuggerManager.getInstance(session.getProject()).getDebugProcess(debugProcess.getProcessHandler()); + if (javaProcess instanceof DebugProcessImpl) { + final DebugProcessImpl processImpl = (DebugProcessImpl)javaProcess; + final ClassesFilteredView classesFilteredView = new ClassesFilteredView(debugProcess.getSession()); + myDispatcher.addListener(visible -> classesFilteredView.setActive(visible), project); - private void removeSession(@NotNull XDebugSession session) { - ClassesFilteredView removed = myMemoryViews.remove(session); - if (removed != null) { - Disposer.dispose(removed); + final MemoryViewDebugProcessData data = new MemoryViewDebugProcessData(classesFilteredView); + final ToolWindow toolWindow = getToolWindow(processImpl.getProject()); + + classesFilteredView.setActive(toolWindow != null && toolWindow.isVisible()); + processImpl.putUserData(MemoryViewDebugProcessData.KEY, data); + + if (toolWindow != null) { + updateCurrentMemoryView(project, toolWindow); + } } } private void updateCurrentMemoryView(@NotNull Project project, @NotNull ToolWindow toolWindow) { + JComponent component = myEmptyContent; if (!project.isDisposed()) { - XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); + final XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); + if (session != null) { - ClassesFilteredView view; - if (myMemoryViews.containsKey(session)) { - view = myMemoryViews.get(session); - replaceToolWindowContent(toolWindow, view); - } - else { - view = null; - replaceToolWindowContent(toolWindow, myMemoryViewNotSupportedContent); - } + final DebugProcess debugProcess = DebuggerManager.getInstance(project) + .getDebugProcess(session.getDebugProcess().getProcessHandler()); + final MemoryViewDebugProcessData data = debugProcess != null ? debugProcess.getUserData(MemoryViewDebugProcessData.KEY) : null; - if (myCurrentView != null) { - myCurrentView.setActive(false); - } - - myCurrentView = view; - return; + component = data != null ? data.getClassesFilteredView() : myMemoryViewNotSupportedContent; } } - replaceToolWindowContent(toolWindow, myEmptyContent); + replaceToolWindowContent(toolWindow, component); } private static void replaceToolWindowContent(@NotNull ToolWindow toolWindow, JComponent comp) { @@ -179,7 +177,7 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware @Override public void processStopped(@NotNull XDebugProcess debugProcess) { - Project project = debugProcess.getSession().getProject(); + final Project project = debugProcess.getSession().getProject(); boolean enabled = Arrays.stream(XDebuggerManager.getInstance(project) .getDebugSessions()).anyMatch(session -> !session.getDebugProcess().equals(debugProcess)); updateIcon(project, enabled); @@ -200,22 +198,26 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware private final class MyDebuggerStatusChangedListener implements XDebuggerManagerListener { @Override public void processStarted(@NotNull XDebugProcess xDebugProcess) { - ApplicationManager.getApplication().invokeLater(() -> { - XDebugSession session = xDebugProcess.getSession(); - addNewSession(session); - updateView(session); - }); + ApplicationManager.getApplication().invokeLater(() -> registerMemoryView(xDebugProcess.getSession())); } @Override public void processStopped(@NotNull XDebugProcess xDebugProcess) { XDebugSession session = xDebugProcess.getSession(); - removeSession(session); + if (xDebugProcess instanceof JavaDebugProcess) { + final DebugProcessImpl process = ((JavaDebugProcess)xDebugProcess).getDebuggerSession().getProcess(); + + final MemoryViewDebugProcessData data = process.getUserData(MemoryViewDebugProcessData.KEY); + if (data != null) { + Disposer.dispose(data.getClassesFilteredView()); + } + } + ApplicationManager.getApplication().invokeLater(() -> updateView(session)); } private void updateView(@NotNull XDebugSession debugSession) { - Project project = debugSession.getProject(); + final Project project = debugSession.getProject(); if (!project.isDisposed()) { ToolWindow toolWindow = getToolWindow(project); if (toolWindow != null) { @@ -224,4 +226,8 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware } } } + + private interface ToolWindowStateListener extends EventListener { + void visibilityChanged(boolean visible); + } } From af10c5eab1aef8f4eb6de78e962c3d2ee28e7156 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Tue, 10 Jan 2017 17:55:05 +0300 Subject: [PATCH 07/13] Do not store debug session/process in classes view --- .../memory/ui/ClassesFilteredView.java | 169 +++++++++++------- 1 file changed, 104 insertions(+), 65 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java index 2cde6e9acf1b..721a12db0a45 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/ClassesFilteredView.java @@ -17,13 +17,11 @@ package com.intellij.debugger.memory.ui; import com.intellij.debugger.DebuggerManager; import com.intellij.debugger.DebuggerManagerEx; +import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.engine.events.DebuggerCommandImpl; -import com.intellij.debugger.memory.component.CreationPositionTracker; -import com.intellij.debugger.memory.component.InstancesTracker; -import com.intellij.debugger.memory.component.MemoryViewManager; -import com.intellij.debugger.memory.component.MemoryViewManagerState; +import com.intellij.debugger.memory.component.*; import com.intellij.debugger.memory.event.InstancesTrackerListener; import com.intellij.debugger.memory.event.MemoryViewManagerListener; import com.intellij.debugger.memory.tracking.ClassPreparedListener; @@ -47,6 +45,7 @@ import com.intellij.util.SmartList; import com.intellij.util.ui.components.BorderLayoutPanel; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebugSessionListener; +import com.intellij.xdebugger.XDebuggerManager; import com.sun.jdi.ObjectReference; import com.sun.jdi.ReferenceType; import com.sun.jdi.VirtualMachine; @@ -63,6 +62,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.IntStream; import static com.intellij.debugger.memory.ui.ClassesTable.DiffViewTableModel.CLASSNAME_COLUMN_INDEX; @@ -77,15 +77,13 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable private static final String EMPTY_TABLE_CONTENT_WHEN_SUSPENDED = "Nothing to show"; private final Project myProject; - private final XDebugSession myDebugSession; - private final DebugProcessImpl myDebugProcess; private final SingleAlarmWithMutableDelay mySingleAlarm; private final SearchTextField myFilterTextField = new FilterTextField(); private final ClassesTable myTable; private final InstancesTracker myInstancesTracker; private final Map myConstructorTrackedClasses = new ConcurrentHashMap<>(); - private final XDebugSessionListener myDebugSessionListener; + private final MyDebuggerSessionListener myDebugSessionListener; @Nullable private volatile SuspendContextImpl myLastSuspendContext; @@ -95,7 +93,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable *

* State: false to true */ - private volatile boolean myIsTrackersActivated = false; + private final AtomicBoolean myIsTrackersActivated = new AtomicBoolean(false); /** * Indicates that view is visible in tool window @@ -106,11 +104,10 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable super(); myProject = debugSession.getProject(); - myDebugSession = debugSession; - myDebugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject) - .getDebugProcess(myDebugSession.getDebugProcess().getProcessHandler()); + final DebugProcessImpl debugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject) + .getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); - if (myDebugProcess == null) { + if (debugProcess == null) { throw new NullPointerException("Failed to receive a java debug process"); } @@ -120,11 +117,12 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable public void classChanged(@NotNull String name, @NotNull TrackingType type) { ReferenceType ref = myTable.getClassByName(name); if (ref != null) { - myDebugProcess.getManagerThread() + final boolean activated = myIsTrackersActivated.get(); + debugProcess.getManagerThread() .schedule(new LowestPriorityCommand(getSuspendContext()) { @Override public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception { - trackClass(ref, type, myIsTrackersActivated); + trackClass(ref, type, activated); } }); } @@ -142,7 +140,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable } }; - myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { + debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { @Override public Priority getPriority() { return Priority.LOWEST; @@ -150,21 +148,22 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable @Override protected void action() throws Exception { + final boolean activated = myIsTrackersActivated.get(); for (Map.Entry entry : myInstancesTracker.getTrackedClasses().entrySet()) { TrackingType type = entry.getValue(); String className = entry.getKey(); - List classes = myDebugProcess.getVirtualMachineProxy().classesByName(className); + List classes = debugProcess.getVirtualMachineProxy().classesByName(className); if (classes.isEmpty()) { - new ClassPreparedListener(className, myDebugSession) { + new ClassPreparedListener(className, debugSession) { @Override public void onClassPrepared(@NotNull ReferenceType referenceType) { - trackClass(referenceType, type, myIsTrackersActivated); + trackClass(referenceType, type, activated); } }; } else { for (ReferenceType ref : classes) { - trackClass(ref, type, myIsTrackersActivated); + trackClass(ref, type, activated); } } } @@ -175,7 +174,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable final MemoryViewManagerState memoryViewManagerState = MemoryViewManager.getInstance().getState(); - myTable = new ClassesTable(myDebugSession, memoryViewManagerState.isShowWithDiffOnly, + myTable = new ClassesTable(debugSession, memoryViewManagerState.isShowWithDiffOnly, memoryViewManagerState.isShowWithInstancesOnly, memoryViewManagerState.isShowTrackedOnly, this); myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_RUNNING); Disposer.register(this, myTable); @@ -235,29 +234,14 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable MemoryViewManager.getInstance().addMemoryViewManagerListener(memoryViewManagerListener, this); - myDebugSessionListener = new XDebugSessionListener() { - @Override - public void sessionResumed() { - myConstructorTrackedClasses.values().forEach(ConstructorInstancesTracker::obsolete); - ApplicationManager.getApplication().invokeLater(() -> { - myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_RUNNING); - myTable.hideContent(); - }); - mySingleAlarm.cancelAllRequests(); - } - - @Override - public void sessionPaused() { - ApplicationManager.getApplication().invokeLater(() -> myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_SUSPENDED)); - updateClassesAndCounts(); - } - }; + myDebugSessionListener = new MyDebuggerSessionListener(); + debugSession.addSessionListener(myDebugSessionListener); mySingleAlarm = new SingleAlarmWithMutableDelay(() -> { myLastSuspendContext = getSuspendContext(); if (myLastSuspendContext != null) { ApplicationManager.getApplication().invokeLater(() -> myTable.setBusy(true)); - myDebugProcess.getManagerThread() + debugProcess.getManagerThread() .schedule(new MyUpdateClassesCommand(myLastSuspendContext)); } }, this); @@ -292,7 +276,12 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable Disposer.dispose(old); } - final ConstructorInstancesTracker tracker = new ConstructorInstancesTracker(ref, myDebugSession); + final XDebugSession debugSession = XDebuggerManager.getInstance(myProject).getCurrentSession(); + if (debugSession == null) { + return; + } + + final ConstructorInstancesTracker tracker = new ConstructorInstancesTracker(ref, debugSession); tracker.setBackgroundMode(!myIsActive); if (isTrackerEnabled) { tracker.enable(); @@ -307,8 +296,9 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable } private void handleClassSelection(@Nullable ReferenceType ref) { - if (ref != null && myDebugSession.isSuspended()) { - new InstancesWindow(myDebugSession, limit -> ref.instances(limit), ref.name()).show(); + final XDebugSession debugSession = XDebuggerManager.getInstance(myProject).getCurrentSession(); + if (ref != null && debugSession != null && debugSession.isSuspended()) { + new InstancesWindow(debugSession, limit -> ref.instances(limit), ref.name()).show(); } } @@ -321,8 +311,13 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable } private void updateClassesAndCounts() { - if (myDebugProcess.isAttached()) { - mySingleAlarm.cancelAndRequest(); + final XDebugSession debugSession = XDebuggerManager.getInstance(myProject).getCurrentSession(); + if (debugSession != null) { + final DebugProcess debugProcess = DebuggerManager.getInstance(myProject) + .getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); + if (debugProcess.isAttached()) { + mySingleAlarm.cancelAndRequest(); + } } } @@ -333,6 +328,7 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable @Override public void dispose() { + myLastSuspendContext = null; } public void setActive(boolean active) { @@ -341,30 +337,36 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable } myIsActive = active; - myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { - @Override - protected void action() throws Exception { - if (active) { - doActivate(); + final XDebugSession debugSession = XDebuggerManager.getInstance(myProject).getCurrentSession(); + if (debugSession != null) { + final DebugProcessImpl debugProcess = + (DebugProcessImpl)DebuggerManager.getInstance(myProject).getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); + debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { + @Override + protected void action() throws Exception { + if (active) { + doActivate(); + } + else { + doPause(); + } } - else { - doPause(); - } - } - }); + }); + } } private void doActivate() { - myDebugSession.addSessionListener(myDebugSessionListener, this); + myDebugSessionListener.setActive(true); myConstructorTrackedClasses.values().forEach(x -> x.setBackgroundMode(false)); final SuspendContextImpl lastContext = myLastSuspendContext; + if (lastContext == null || !lastContext.equals(getSuspendContext())) { updateClassesAndCounts(); } } private void doPause() { - myDebugSession.removeSessionListener(myDebugSessionListener); + myDebugSessionListener.setActive(false); myConstructorTrackedClasses.values().forEach(x -> x.setBackgroundMode(true)); } @@ -376,14 +378,15 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable @Override public void contextAction(@NotNull SuspendContextImpl suspendContext) throws Exception { - if (!myIsTrackersActivated) { + if (!myIsTrackersActivated.get()) { myConstructorTrackedClasses.values().forEach(ConstructorInstancesTracker::enable); - myIsTrackersActivated = true; + myIsTrackersActivated.set(true); } else { commitAllTrackers(); } - final List classes = myDebugProcess.getVirtualMachineProxy().allClasses(); + + final List classes = suspendContext.getDebugProcess().getVirtualMachineProxy().allClasses(); if (classes.isEmpty()) { return; @@ -449,15 +452,23 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable return; } - final CreationPositionTracker tracker = CreationPositionTracker.getInstance(myDebugSession.getProject()); final ReferenceType ref = myTable.getSelectedClass(); final TrackerForNewInstances strategy = ref == null ? null : getStrategy(ref); - if (strategy != null && tracker != null) { - List newInstances = strategy.getNewInstances(); - tracker.pinStacks(myDebugSession, ref); - InstancesWindow instancesWindow = new InstancesWindow(myDebugSession, limit -> newInstances, ref.name()); - Disposer.register(instancesWindow.getDisposable(), () -> tracker.unpinStacks(myDebugSession, ref)); - instancesWindow.show(); + XDebugSession debugSession = XDebuggerManager.getInstance(myProject).getCurrentSession(); + if (strategy != null && debugSession != null) { + final DebugProcess debugProcess = + DebuggerManager.getInstance(myProject).getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); + final MemoryViewDebugProcessData data = debugProcess.getUserData(MemoryViewDebugProcessData.KEY); + if (data != null) { + final List newInstances = strategy.getNewInstances(); + data.getTrackedStacks().pinStacks(ref); + final InstancesWindow instancesWindow = new InstancesWindow(debugSession, limit -> newInstances, ref.name()); + Disposer.register(instancesWindow.getDisposable(), () -> data.getTrackedStacks().unpinStacks(ref)); + instancesWindow.show(); + } + else { + LOG.warn("MemoryViewDebugProcessData not found in debug session user data"); + } } } } @@ -504,4 +515,32 @@ public class ClassesFilteredView extends BorderLayoutPanel implements Disposable return tracker != null && tracker.isReady() && tracker.getCount() > 0; } + + private class MyDebuggerSessionListener implements XDebugSessionListener { + private volatile boolean myIsActive = false; + + void setActive(boolean value) { + myIsActive = value; + } + + @Override + public void sessionResumed() { + if (myIsActive) { + myConstructorTrackedClasses.values().forEach(ConstructorInstancesTracker::obsolete); + ApplicationManager.getApplication().invokeLater(() -> { + myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_RUNNING); + myTable.hideContent(); + }); + mySingleAlarm.cancelAllRequests(); + } + } + + @Override + public void sessionPaused() { + if (myIsActive) { + ApplicationManager.getApplication().invokeLater(() -> myTable.getEmptyText().setText(EMPTY_TABLE_CONTENT_WHEN_SUSPENDED)); + updateClassesAndCounts(); + } + } + } } From 2c0b50c1ce4abd4993aba4b4bab1c57be1390024 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Tue, 10 Jan 2017 17:58:19 +0300 Subject: [PATCH 08/13] Fix parent disposable for toolwindow visibility listener --- .../debugger/memory/toolwindow/MemoryViewToolWindowFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java b/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java index f614b1caa51e..5b79d19dccc7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java @@ -121,7 +121,7 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware if (javaProcess instanceof DebugProcessImpl) { final DebugProcessImpl processImpl = (DebugProcessImpl)javaProcess; final ClassesFilteredView classesFilteredView = new ClassesFilteredView(debugProcess.getSession()); - myDispatcher.addListener(visible -> classesFilteredView.setActive(visible), project); + myDispatcher.addListener(visible -> classesFilteredView.setActive(visible), classesFilteredView); final MemoryViewDebugProcessData data = new MemoryViewDebugProcessData(classesFilteredView); final ToolWindow toolWindow = getToolWindow(processImpl.getProject()); From ed876f92929bd9818a9154b12d36ba8b3213a292 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Tue, 10 Jan 2017 18:01:03 +0300 Subject: [PATCH 09/13] Add interface for container with stack-frames which was tracked --- .../component/TrackedStacksContainer.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 java/debugger/impl/src/com/intellij/debugger/memory/component/TrackedStacksContainer.java diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/component/TrackedStacksContainer.java b/java/debugger/impl/src/com/intellij/debugger/memory/component/TrackedStacksContainer.java new file mode 100644 index 000000000000..b4e34b9e2a80 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/memory/component/TrackedStacksContainer.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.memory.component; + +import com.intellij.debugger.memory.utils.StackFrameItem; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Vitaliy.Bibaev + */ +public interface TrackedStacksContainer { + @Nullable + List getStack(@NotNull ObjectReference reference); + + void addStack(@NotNull ObjectReference ref, @NotNull List frames); + + void pinStacks(@NotNull ReferenceType referenceType); + + void unpinStacks(@NotNull ReferenceType referenceType); + + void release(); +} From d4d7c7a310718aa583ae65553ad85f0dfebd9b2b Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Tue, 10 Jan 2017 18:05:14 +0300 Subject: [PATCH 10/13] Replace CreationPositionTracker project component with MemoryViewDebugProcessData object associated with a DebugProcess --- .../JumpToAllocationSourceAction.java | 12 +- .../component/CreationPositionTracker.java | 117 ------------------ .../component/MemoryViewDebugProcessData.java | 56 ++++++++- .../tracking/ConstructorInstancesTracker.java | 36 +++--- .../ui/InstancesWithStackFrameView.java | 19 +-- resources/src/componentSets/Debugger.xml | 4 - 6 files changed, 92 insertions(+), 152 deletions(-) delete mode 100644 java/debugger/impl/src/com/intellij/debugger/memory/component/CreationPositionTracker.java diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java index c08a619a3d78..489ae76d6f06 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java @@ -17,7 +17,7 @@ package com.intellij.debugger.memory.action.tracking; import com.intellij.debugger.DebuggerManager; import com.intellij.debugger.memory.action.DebuggerTreeAction; -import com.intellij.debugger.memory.component.CreationPositionTracker; +import com.intellij.debugger.memory.component.MemoryViewDebugProcessData; import com.intellij.debugger.memory.ui.StackFramePopup; import com.intellij.debugger.memory.utils.StackFrameItem; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -62,7 +62,13 @@ public class JumpToAllocationSourceAction extends DebuggerTreeAction { } final XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); - final CreationPositionTracker tracker = CreationPositionTracker.getInstance(project); - return session != null && tracker != null ? tracker.getStack(session, ref) : null; + if (session != null) { + final MemoryViewDebugProcessData data = + DebuggerManager.getInstance(project).getDebugProcess(session.getDebugProcess().getProcessHandler()).getUserData( + MemoryViewDebugProcessData.KEY); + return data != null ? data.getTrackedStacks().getStack(ref) : null; + } + + return null; } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/component/CreationPositionTracker.java b/java/debugger/impl/src/com/intellij/debugger/memory/component/CreationPositionTracker.java deleted file mode 100644 index ca8c6a9a2f87..000000000000 --- a/java/debugger/impl/src/com/intellij/debugger/memory/component/CreationPositionTracker.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.debugger.memory.component; - -import com.intellij.debugger.memory.utils.StackFrameItem; -import com.intellij.openapi.components.AbstractProjectComponent; -import com.intellij.openapi.project.Project; -import com.intellij.xdebugger.XDebugSession; -import com.intellij.xdebugger.XDebugSessionListener; -import com.sun.jdi.ObjectReference; -import com.sun.jdi.ReferenceType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -public class CreationPositionTracker extends AbstractProjectComponent { - /** - * Stores all tracked instance for each debug session. - */ - private final ConcurrentHashMap>> - mySession2Reference2Stack = new ConcurrentHashMap<>(); - - private final ConcurrentHashMap>> - myPinnedSession2Reference2Stack = new ConcurrentHashMap<>(); - - public CreationPositionTracker(@NotNull Project project) { - super(project); - } - - @Nullable - public static CreationPositionTracker getInstance(@NotNull Project project) { - return project.isDisposed() ? null : project.getComponent(CreationPositionTracker.class); - } - - @Nullable - public List getStack(@NotNull XDebugSession session, @NotNull ObjectReference ref) { - final List stack = extract(mySession2Reference2Stack, session, ref); - return stack != null ? stack : extract(myPinnedSession2Reference2Stack, session, ref); - } - - public void addStack(@NotNull XDebugSession session, @NotNull ObjectReference ref, - @NotNull List stack) { - if (!mySession2Reference2Stack.containsKey(session)) { - mySession2Reference2Stack.put(session, new ConcurrentHashMap<>()); - session.addSessionListener(new XDebugSessionListener() { - @Override - public void sessionStopped() { - mySession2Reference2Stack.remove(session); - } - }); - } - - mySession2Reference2Stack.get(session).put(ref, stack); - } - - public void releaseBySession(@NotNull XDebugSession session) { - if (mySession2Reference2Stack.containsKey(session)) { - mySession2Reference2Stack.put(session, new ConcurrentHashMap<>()); - } - } - - public void unpinStacks(@NotNull XDebugSession session, @NotNull ReferenceType ref) { - final Map> ref2Stack = myPinnedSession2Reference2Stack.get(session); - if (ref2Stack != null) { - final Iterator iterator = ref2Stack.keySet().iterator(); - while (iterator.hasNext()) { - final ObjectReference reference = iterator.next(); - if (ref.equals(reference.referenceType())) { - iterator.remove(); - } - } - - if (ref2Stack.isEmpty()) { - myPinnedSession2Reference2Stack.remove(session); - } - } - } - - public void pinStacks(@NotNull XDebugSession session, @NotNull ReferenceType ref) { - final Map> ref2Stack = mySession2Reference2Stack.get(session); - if (ref2Stack != null) { - final Map> ref2StacksByReferenceType = ref2Stack.entrySet().stream() - .filter(entry -> ref.equals(entry.getKey().referenceType())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - myPinnedSession2Reference2Stack.put(session, ref2StacksByReferenceType); - } - } - - @Nullable - private static T extract(@NotNull Map> map, - @NotNull XDebugSession session, @NotNull ObjectReference ref) { - final Map ref2something = map.get(session); - if (ref2something != null) { - return ref2something.get(ref); - } - - return null; - } -} diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/component/MemoryViewDebugProcessData.java b/java/debugger/impl/src/com/intellij/debugger/memory/component/MemoryViewDebugProcessData.java index a378a66ab891..8433e9ce1cb2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/component/MemoryViewDebugProcessData.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/component/MemoryViewDebugProcessData.java @@ -19,6 +19,7 @@ import com.intellij.debugger.memory.ui.ClassesFilteredView; import com.intellij.debugger.memory.utils.StackFrameItem; import com.intellij.openapi.util.Key; import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,20 +33,63 @@ import java.util.concurrent.ConcurrentHashMap; public class MemoryViewDebugProcessData { public static final Key KEY = Key.create("MemoryView.DebugProcessData"); + private final TrackedStacksContainer myStacksContainer = new MyStackContainer(); private final ClassesFilteredView myClassesFilteredView; - private final Map> myTrackedFrames = new ConcurrentHashMap<>(); public MemoryViewDebugProcessData(@NotNull ClassesFilteredView classesView) { myClassesFilteredView = classesView; } - @Nullable - List getStackFrames(@NotNull ObjectReference reference) { - return myTrackedFrames.get(reference); - } - @NotNull public ClassesFilteredView getClassesFilteredView() { return myClassesFilteredView; } + + @NotNull + public TrackedStacksContainer getTrackedStacks() { + return myStacksContainer; + } + + private static class MyStackContainer implements TrackedStacksContainer { + private final Map>> myType2Reference2Stack = new ConcurrentHashMap<>(); + + private final Map>> myPinnedType2Reference2Stack = new ConcurrentHashMap<>(); + + @Nullable + @Override + public List getStack(@NotNull ObjectReference reference) { + final List stack = extract(myType2Reference2Stack, reference); + return stack != null ? stack : extract(myPinnedType2Reference2Stack, reference); + } + + @Override + public void addStack(@NotNull ObjectReference ref, @NotNull List frames) { + myType2Reference2Stack.computeIfAbsent(ref.referenceType(), referenceType -> new ConcurrentHashMap<>()).put(ref, frames); + } + + @Override + public void pinStacks(@NotNull ReferenceType referenceType) { + final Map> ref2Stack = myType2Reference2Stack.get(referenceType); + if (ref2Stack != null) { + myPinnedType2Reference2Stack.put(referenceType, ref2Stack); + } + } + + @Override + public void unpinStacks(@NotNull ReferenceType referenceType) { + myPinnedType2Reference2Stack.remove(referenceType); + } + + @Override + public void release() { + myType2Reference2Stack.clear(); + } + + @Nullable + private static List extract(@NotNull Map>> map, + @NotNull ObjectReference ref) { + final Map> ref2Stack = map.get(ref.referenceType()); + return ref2Stack != null ? ref2Stack.get(ref) : null; + } + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ConstructorInstancesTracker.java b/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ConstructorInstancesTracker.java index cb72cd539d15..1d4775262c43 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ConstructorInstancesTracker.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ConstructorInstancesTracker.java @@ -16,13 +16,14 @@ package com.intellij.debugger.memory.tracking; import com.intellij.debugger.DebuggerManager; +import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.engine.events.SuspendContextCommandImpl; -import com.intellij.debugger.memory.component.CreationPositionTracker; import com.intellij.debugger.memory.component.InstancesTracker; +import com.intellij.debugger.memory.component.MemoryViewDebugProcessData; import com.intellij.debugger.memory.event.InstancesTrackerListener; import com.intellij.debugger.memory.utils.StackFrameItem; import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType; @@ -55,8 +56,7 @@ import java.util.List; public class ConstructorInstancesTracker implements TrackerForNewInstances, Disposable, BackgroundTracker { private static final int TRACKED_INSTANCES_LIMIT = 2000; private final ReferenceType myReference; - private final XDebugSession myDebugSession; - private final CreationPositionTracker myPositionTracker; + private final Project myProject; private final DebugProcessImpl myDebugProcess; private final MyConstructorBreakpoints myBreakpoint; @@ -72,13 +72,11 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp public ConstructorInstancesTracker(@NotNull ReferenceType ref, @NotNull XDebugSession debugSession) { myReference = ref; - myDebugSession = debugSession; - myPositionTracker = CreationPositionTracker.getInstance(debugSession.getProject()); - Project project = debugSession.getProject(); - myIsBackgroundTrackingEnabled = InstancesTracker.getInstance(myDebugSession.getProject()) + myProject = debugSession.getProject(); + myIsBackgroundTrackingEnabled = InstancesTracker.getInstance(myProject) .isBackgroundTrackingEnabled(); - InstancesTracker.getInstance(myDebugSession.getProject()).addTrackerListener(new InstancesTrackerListener() { + InstancesTracker.getInstance(myProject).addTrackerListener(new InstancesTrackerListener() { @Override public void backgroundTrackingValueChanged(boolean newState) { if (myIsBackgroundTrackingEnabled != newState) { @@ -98,16 +96,16 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp } }, this); - myDebugProcess = (DebugProcessImpl)DebuggerManager.getInstance(project) + myDebugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject) .getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); JavaLineBreakpointType breakPointType = new JavaLineBreakpointType(); XBreakpoint bpn = new XLineBreakpointImpl<>(breakPointType, - ((XDebuggerManagerImpl)XDebuggerManager.getInstance(project)).getBreakpointManager(), + ((XDebuggerManagerImpl)XDebuggerManager.getInstance(myProject)).getBreakpointManager(), new JavaLineBreakpointProperties(), new LineBreakpointState<>()); - myBreakpoint = new MyConstructorBreakpoints(project, bpn); + myBreakpoint = new MyConstructorBreakpoints(myProject, bpn); myBreakpoint.createRequestForPreparedClass(myDebugProcess, myReference); } @@ -120,7 +118,15 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp if (!myIsBackgroundMode || myIsBackgroundTrackingEnabled) { myBreakpoint.enable(); } - myPositionTracker.releaseBySession(myDebugSession); + + final XDebugSession session = XDebuggerManager.getInstance(myProject).getCurrentSession(); + if (session != null) { + final DebugProcess process = DebuggerManager.getInstance(myProject).getDebugProcess(session.getDebugProcess().getProcessHandler()); + final MemoryViewDebugProcessData data = process.getUserData(MemoryViewDebugProcessData.KEY); + if (data != null) { + data.getTrackedStacks().release(); + } + } } public void commitTracked() { @@ -227,11 +233,13 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp try { SuspendContextImpl suspendContext = action.getSuspendContext(); if (suspendContext != null) { + final MemoryViewDebugProcessData data = suspendContext.getDebugProcess().getUserData(MemoryViewDebugProcessData.KEY); ObjectReference thisRef = getThisObject(suspendContext, event); - if (myReference.equals(thisRef.referenceType()) && myPositionTracker != null) { + if (myReference.equals(thisRef.referenceType()) && data != null) { thisRef.disableCollection(); myTrackedObjects.add(thisRef); - myPositionTracker.addStack(myDebugSession, thisRef, StackFrameItem.createFrames(suspendContext.getThread())); + final List frame = StackFrameItem.createFrames(suspendContext.getThread()); + data.getTrackedStacks().addStack(thisRef, frame); } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWithStackFrameView.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWithStackFrameView.java index 234d6330f7a1..23d678182978 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWithStackFrameView.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWithStackFrameView.java @@ -15,6 +15,12 @@ */ package com.intellij.debugger.memory.ui; +import com.intellij.debugger.DebuggerManager; +import com.intellij.debugger.memory.component.InstancesTracker; +import com.intellij.debugger.memory.component.MemoryViewDebugProcessData; +import com.intellij.debugger.memory.event.InstancesTrackerListener; +import com.intellij.debugger.memory.tracking.TrackingType; +import com.intellij.debugger.memory.utils.StackFrameItem; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -25,11 +31,6 @@ import com.intellij.ui.components.labels.ActionLink; import com.intellij.xdebugger.XDebugSession; import com.sun.jdi.ObjectReference; import org.jetbrains.annotations.NotNull; -import com.intellij.debugger.memory.component.CreationPositionTracker; -import com.intellij.debugger.memory.component.InstancesTracker; -import com.intellij.debugger.memory.event.InstancesTrackerListener; -import com.intellij.debugger.memory.tracking.TrackingType; -import com.intellij.debugger.memory.utils.StackFrameItem; import javax.swing.*; import java.util.Collections; @@ -77,7 +78,6 @@ class InstancesWithStackFrameView { JComponent stackComponent = new JBScrollPane(list); - CreationPositionTracker tracker = CreationPositionTracker.getInstance(debugSession.getProject()); InstancesTracker instancesTracker = InstancesTracker.getInstance(debugSession.getProject()); instancesTracker.addTrackerListener(new InstancesTrackerListener() { @Override @@ -100,10 +100,13 @@ class InstancesWithStackFrameView { mySplitter.setHonorComponentsMinimumSize(false); myHidedProportion = DEFAULT_SPLITTER_PROPORTION; + final MemoryViewDebugProcessData data = + DebuggerManager.getInstance(debugSession.getProject()).getDebugProcess(debugSession.getDebugProcess().getProcessHandler()) + .getUserData(MemoryViewDebugProcessData.KEY); tree.addTreeSelectionListener(e -> { ObjectReference ref = tree.getSelectedReference(); - if (ref != null && tracker != null) { - List stack = tracker.getStack(debugSession, ref); + if (ref != null && data != null) { + List stack = data.getTrackedStacks().getStack(ref); if (stack != null) { list.setFrame(stack); if (mySplitter.getProportion() == 1.f) { diff --git a/resources/src/componentSets/Debugger.xml b/resources/src/componentSets/Debugger.xml index 2a8751ee98e0..deea1b445d1d 100644 --- a/resources/src/componentSets/Debugger.xml +++ b/resources/src/componentSets/Debugger.xml @@ -29,10 +29,6 @@ com.intellij.debugger.memory.component.InstancesTracker - - - com.intellij.debugger.memory.component.CreationPositionTracker - From 60fa76f664cca14fb0987a38a0ff2bc9de55d83e Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Tue, 10 Jan 2017 18:27:22 +0300 Subject: [PATCH 11/13] Do not store a debug process in ConstructorInstancesTracker --- .../tracking/ConstructorInstancesTracker.java | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ConstructorInstancesTracker.java b/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ConstructorInstancesTracker.java index 1d4775262c43..549da0518f93 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ConstructorInstancesTracker.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/tracking/ConstructorInstancesTracker.java @@ -57,7 +57,6 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp private static final int TRACKED_INSTANCES_LIMIT = 2000; private final ReferenceType myReference; private final Project myProject; - private final DebugProcessImpl myDebugProcess; private final MyConstructorBreakpoints myBreakpoint; @Nullable @@ -76,12 +75,15 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp myIsBackgroundTrackingEnabled = InstancesTracker.getInstance(myProject) .isBackgroundTrackingEnabled(); + final DebugProcessImpl debugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject) + .getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); + InstancesTracker.getInstance(myProject).addTrackerListener(new InstancesTrackerListener() { @Override public void backgroundTrackingValueChanged(boolean newState) { if (myIsBackgroundTrackingEnabled != newState) { myIsBackgroundTrackingEnabled = newState; - myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { + debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { @Override protected void action() throws Exception { if (newState) { @@ -96,17 +98,24 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp } }, this); - myDebugProcess = (DebugProcessImpl)DebuggerManager.getInstance(myProject) - .getDebugProcess(debugSession.getDebugProcess().getProcessHandler()); - JavaLineBreakpointType breakPointType = new JavaLineBreakpointType(); + final JavaLineBreakpointType breakPointType = new JavaLineBreakpointType(); - XBreakpoint bpn = new XLineBreakpointImpl<>(breakPointType, - ((XDebuggerManagerImpl)XDebuggerManager.getInstance(myProject)).getBreakpointManager(), - new JavaLineBreakpointProperties(), - new LineBreakpointState<>()); + final XBreakpoint bpn = new XLineBreakpointImpl<>(breakPointType, + ((XDebuggerManagerImpl)XDebuggerManager.getInstance(myProject)) + .getBreakpointManager(), + new JavaLineBreakpointProperties(), + new LineBreakpointState<>()); myBreakpoint = new MyConstructorBreakpoints(myProject, bpn); - myBreakpoint.createRequestForPreparedClass(myDebugProcess, myReference); + myBreakpoint.createRequestForPreparedClass(debugProcess, myReference); + Disposer.register(myBreakpoint, () -> debugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { + @Override + protected void action() throws Exception { + disable(); + debugProcess.getRequestsManager().deleteRequest(myBreakpoint); + myBreakpoint.delete(); + } + })); } public void obsolete() { @@ -189,8 +198,8 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp } private final class MyConstructorBreakpoints extends LineBreakpoint implements Disposable { - private boolean myIsEnabled = false; private final List myRequests = new ArrayList<>(); + private volatile boolean myIsEnabled = false; private volatile boolean myIsDeleted = false; MyConstructorBreakpoints(Project project, XBreakpoint xBreakpoint) { @@ -215,16 +224,12 @@ public class ConstructorInstancesTracker implements TrackerForNewInstances, Disp public void reload() { } + void delete() { + myIsDeleted = true; + } + @Override public void dispose() { - myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() { - @Override - protected void action() throws Exception { - disable(); - myDebugProcess.getRequestsManager().deleteRequest(MyConstructorBreakpoints.this); - myIsDeleted = true; - } - }); } @Override From f06eaf12e8d06334d366773929b11d7ef1d40a9d Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Wed, 11 Jan 2017 13:52:40 +0300 Subject: [PATCH 12/13] Add final modifiers, small refactoring --- .../debugger/memory/ui/InstancesWindow.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java index 93734dcf9b87..619eb6fd1dc4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java @@ -87,7 +87,7 @@ public class InstancesWindow extends DialogWrapper { private final DebugProcessImpl myDebugProcess; private final InstancesProvider myInstancesProvider; private final String myClassName; - private MyInstancesView myInstancesView; + private final MyInstancesView myInstancesView; public InstancesWindow(@NotNull XDebugSession session, @NotNull InstancesProvider provider, @@ -178,25 +178,25 @@ public class InstancesWindow extends DialogWrapper { super(new BorderLayout(0, JBUI.scale(BORDER_LAYOUT_DEFAULT_GAP))); Disposer.register(InstancesWindow.this.myDisposable, this); - XValueMarkers markers = getValueMarkers(session); + final XValueMarkers markers = getValueMarkers(session); if (markers != null) { final MyActionListener listener = new MyActionListener(markers); ActionManager.getInstance().addAnActionListener(listener, InstancesWindow.this.myDisposable); } session.addSessionListener(myDebugSessionListener, InstancesWindow.this.myDisposable); - JavaDebuggerEditorsProvider editorsProvider = new JavaDebuggerEditorsProvider(); + final JavaDebuggerEditorsProvider editorsProvider = new JavaDebuggerEditorsProvider(); myFilterConditionEditor = new ExpressionEditorWithHistory(myProject, myClassName, editorsProvider, InstancesWindow.this.myDisposable); myFilterButton.setBorder(BorderFactory.createEmptyBorder()); - Dimension filteringButtonSize = myFilterConditionEditor.getEditorComponent().getPreferredSize(); + final Dimension filteringButtonSize = myFilterConditionEditor.getEditorComponent().getPreferredSize(); filteringButtonSize.width = JBUI.scale(FILTERING_BUTTON_ADDITIONAL_WIDTH) + myFilterButton.getPreferredSize().width; myFilterButton.setPreferredSize(filteringButtonSize); - JBPanel filteringPane = new JBPanel(new BorderLayout(JBUI.scale(BORDER_LAYOUT_DEFAULT_GAP), 0)); - JBLabel sideEffectsWarning = new JBLabel("Warning: filtering may have side effects", SwingConstants.RIGHT); + final JBPanel filteringPane = new JBPanel(new BorderLayout(JBUI.scale(BORDER_LAYOUT_DEFAULT_GAP), 0)); + final JBLabel sideEffectsWarning = new JBLabel("Warning: filtering may have side effects", SwingConstants.RIGHT); sideEffectsWarning.setBorder(JBUI.Borders.empty(1, 0, 0, 0)); sideEffectsWarning.setComponentStyle(UIUtil.ComponentStyle.SMALL); sideEffectsWarning.setFontColor(UIUtil.FontColor.BRIGHTER); @@ -211,7 +211,7 @@ public class InstancesWindow extends DialogWrapper { myInstancesTree = new InstancesTree(myProject, editorsProvider, markers, this::updateInstances); myFilterButton.addActionListener(e -> { - String expression = myFilterConditionEditor.getExpression().getExpression(); + final String expression = myFilterConditionEditor.getExpression().getExpression(); if (!expression.isEmpty()) { myFilterConditionEditor.saveTextInHistory(); } @@ -221,7 +221,7 @@ public class InstancesWindow extends DialogWrapper { }); - StackFrameList list = new StackFrameList(myProject, + final StackFrameList list = new StackFrameList(myProject, Collections.emptyList(), GlobalSearchScope.allScope(myProject)); @@ -234,13 +234,13 @@ public class InstancesWindow extends DialogWrapper { } }.installOn(list); - InstancesWithStackFrameView instancesWithStackFrame = new InstancesWithStackFrameView(session, + final InstancesWithStackFrameView instancesWithStackFrame = new InstancesWithStackFrameView(session, myInstancesTree, list, myClassName); add(filteringPane, BorderLayout.NORTH); add(instancesWithStackFrame.getComponent(), BorderLayout.CENTER); - JComponent focusedComponent = myFilterConditionEditor.getEditorComponent(); + final JComponent focusedComponent = myFilterConditionEditor.getEditorComponent(); UiNotifyConnector.doWhenFirstShown(focusedComponent, () -> IdeFocusManager.findInstanceByComponent(focusedComponent) .requestFocus(focusedComponent, true)); @@ -264,12 +264,12 @@ public class InstancesWindow extends DialogWrapper { @Override public void threadAction(@NotNull SuspendContextImpl suspendContext) { myIsAndroidVM = AndroidUtil.isAndroidVM(myDebugProcess.getVirtualMachineProxy().getVirtualMachine()); - int limit = myIsAndroidVM - ? AndroidUtil.ANDROID_INSTANCES_LIMIT - : DEFAULT_INSTANCES_LIMIT; + final int limit = myIsAndroidVM + ? AndroidUtil.ANDROID_INSTANCES_LIMIT + : DEFAULT_INSTANCES_LIMIT; List instances = myInstancesProvider.getInstances(limit + 1); - EvaluationContextImpl evaluationContext = myDebugProcess + final EvaluationContextImpl evaluationContext = myDebugProcess .getDebuggerContext().createEvaluationContext(); if (instances.size() > limit) { @@ -336,9 +336,9 @@ public class InstancesWindow extends DialogWrapper { @Override public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { - if (dataContext.getData(PlatformDataKeys.CONTEXT_COMPONENT) == myInstancesView.myInstancesTree && + if (dataContext.getData(PlatformDataKeys.CONTEXT_COMPONENT) == myInstancesTree && (isAddToWatchesAction(action) || isEvaluateExpressionAction(action))) { - final XValueNodeImpl selectedNode = XDebuggerTreeActionBase.getSelectedNode(dataContext); + XValueNodeImpl selectedNode = XDebuggerTreeActionBase.getSelectedNode(dataContext); if (selectedNode != null) { TreeNode currentNode = selectedNode; From dd438303218fc30dd22c6fb82263f216a6810237 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Wed, 11 Jan 2017 16:50:29 +0300 Subject: [PATCH 13/13] Disable memory view when toolwindow hidden --- .../MemoryViewToolWindowFactory.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java b/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java index 5b79d19dccc7..7cfd031f01e6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/toolwindow/MemoryViewToolWindowFactory.java @@ -73,7 +73,7 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware @Override public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { - MessageBusConnection connection = project.getMessageBus().connect(project); + final MessageBusConnection connection = project.getMessageBus().connect(project); connection.subscribe(XDebuggerManager.TOPIC, new MyDebuggerStatusChangedListener()); connection.subscribe(RunContentManager.TOPIC, new RunContentWithExecutorListener() { @Override @@ -95,7 +95,7 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware if (isVisible != myIsToolWindowVisible) { myDispatcher.getMulticaster().visibilityChanged(isVisible); - myIsToolWindowVisible ^= myIsToolWindowVisible; + myIsToolWindowVisible = isVisible; } } }, project); @@ -154,7 +154,7 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware private static void replaceToolWindowContent(@NotNull ToolWindow toolWindow, JComponent comp) { LOG.assertTrue(SwingUtilities.isEventDispatchThread()); - JComponent toolWindowComp = toolWindow.getComponent(); + final JComponent toolWindowComp = toolWindow.getComponent(); toolWindowComp.removeAll(); toolWindowComp.add(comp); toolWindowComp.repaint(); @@ -168,7 +168,7 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware public static class Condition implements com.intellij.openapi.util.Condition { @Override public boolean value(Project project) { - MessageBusConnection connection = project.getMessageBus().connect(project); + final MessageBusConnection connection = project.getMessageBus().connect(project); connection.subscribe(XDebuggerManager.TOPIC, new XDebuggerManagerListener() { @Override public void processStarted(@NotNull XDebugProcess debugProcess) { @@ -178,15 +178,15 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware @Override public void processStopped(@NotNull XDebugProcess debugProcess) { final Project project = debugProcess.getSession().getProject(); - boolean enabled = Arrays.stream(XDebuggerManager.getInstance(project) - .getDebugSessions()).anyMatch(session -> !session.getDebugProcess().equals(debugProcess)); + final boolean enabled = Arrays.stream(XDebuggerManager.getInstance(project) + .getDebugSessions()).anyMatch(session -> !session.getDebugProcess().equals(debugProcess)); updateIcon(project, enabled); } private void updateIcon(@NotNull Project project, boolean enabled) { - ToolWindow toolWindow = MemoryViewManager.getInstance().getToolWindow(project); + final ToolWindow toolWindow = MemoryViewManager.getInstance().getToolWindow(project); if (toolWindow != null) { - Icon icon = enabled ? AllIcons.Debugger.MemoryView.ToolWindowEnabled : AllIcons.Debugger.MemoryView.ToolWindowDisabled; + final Icon icon = enabled ? AllIcons.Debugger.MemoryView.ToolWindowEnabled : AllIcons.Debugger.MemoryView.ToolWindowDisabled; ApplicationManager.getApplication().invokeLater(() -> toolWindow.setIcon(icon)); } } @@ -203,7 +203,7 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware @Override public void processStopped(@NotNull XDebugProcess xDebugProcess) { - XDebugSession session = xDebugProcess.getSession(); + final XDebugSession session = xDebugProcess.getSession(); if (xDebugProcess instanceof JavaDebugProcess) { final DebugProcessImpl process = ((JavaDebugProcess)xDebugProcess).getDebuggerSession().getProcess(); @@ -219,7 +219,7 @@ public class MemoryViewToolWindowFactory implements ToolWindowFactory, DumbAware private void updateView(@NotNull XDebugSession debugSession) { final Project project = debugSession.getProject(); if (!project.isDisposed()) { - ToolWindow toolWindow = getToolWindow(project); + final ToolWindow toolWindow = getToolWindow(project); if (toolWindow != null) { updateCurrentMemoryView(project, toolWindow); }