diff --git a/.idea/libraries/debugger_memory_agent.xml b/.idea/libraries/debugger_memory_agent.xml
index cc7ebf5ece1d..2f846d4d5f63 100644
--- a/.idea/libraries/debugger_memory_agent.xml
+++ b/.idea/libraries/debugger_memory_agent.xml
@@ -1,12 +1,12 @@
-
+
-
+
-
+
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowGarbageCollectorRootsAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowGarbageCollectorRootsAction.java
index c5c9aec1ee2f..4f0fc0791159 100644
--- a/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowGarbageCollectorRootsAction.java
+++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/ShowGarbageCollectorRootsAction.java
@@ -18,11 +18,12 @@ import com.sun.jdi.ObjectReference;
import org.jetbrains.annotations.NotNull;
public class ShowGarbageCollectorRootsAction extends NativeAgentActionBase {
+ private static final int DEFAULT_OBJECTS_LIMIT = 1000;
@Override
protected void perform(@NotNull MemoryAgent memoryAgent,
@NotNull ObjectReference reference,
@NotNull XValueNodeImpl node) throws EvaluateException {
- ReferringObjectsProvider roots = memoryAgent.canFindGcRoots() ? memoryAgent.findGcRoots(reference) : null;
+ ReferringObjectsProvider roots = memoryAgent.canFindGcRoots() ? memoryAgent.findGcRoots(reference, DEFAULT_OBJECTS_LIMIT) : null;
if (roots == null) {
XDebuggerManagerImpl.NOTIFICATION_GROUP.createNotification("This feature is unavailable", NotificationType.INFORMATION);
return;
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/AgentLoader.java b/java/debugger/impl/src/com/intellij/debugger/memory/agent/AgentLoader.java
index 9851010c8faa..41a0166ffb05 100644
--- a/java/debugger/impl/src/com/intellij/debugger/memory/agent/AgentLoader.java
+++ b/java/debugger/impl/src/com/intellij/debugger/memory/agent/AgentLoader.java
@@ -106,7 +106,7 @@ public class AgentLoader {
}
@Override
- public ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference) {
+ public ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference, int limit) {
throw new UnsupportedOperationException();
}
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgent.java b/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgent.java
index c6ec09914f2a..23deeaadfe33 100644
--- a/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgent.java
+++ b/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgent.java
@@ -23,5 +23,5 @@ public interface MemoryAgent {
boolean canFindGcRoots();
@Nullable
- ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference) throws EvaluateException;
+ ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference, int limit) throws EvaluateException;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgentImpl.java b/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgentImpl.java
index 3149a1f18ace..c2d963a60375 100644
--- a/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgentImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgentImpl.java
@@ -11,13 +11,11 @@ import com.intellij.debugger.memory.agent.parsers.BooleanParser;
import com.intellij.debugger.memory.agent.parsers.GcRootsPathsParser;
import com.intellij.debugger.memory.agent.parsers.LongValueParser;
import com.intellij.openapi.diagnostic.Logger;
-import com.sun.jdi.ClassType;
-import com.sun.jdi.Method;
-import com.sun.jdi.ObjectReference;
-import com.sun.jdi.Value;
+import com.sun.jdi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -60,7 +58,7 @@ public class MemoryAgentImpl implements MemoryAgent {
public long evaluateObjectSize(@NotNull ObjectReference reference) throws EvaluateException {
if (!canEvaluateObjectSize()) throw new UnsupportedOperationException();
Value result = callMethod(SIZE_OF_SINGLE_OBJECT_METHOD_NAME, Collections.singletonList(reference));
- return result != null ? new LongValueParser().parse(result) : -1;
+ return result != null ? LongValueParser.INSTANCE.parse(result) : -1;
}
@Override
@@ -83,11 +81,12 @@ public class MemoryAgentImpl implements MemoryAgent {
@Nullable
@Override
- public ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference) throws EvaluateException {
+ public ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference, int limit) throws EvaluateException {
if (!canFindGcRoots()) throw new UnsupportedOperationException();
- Value value = callMethod(GARBAGE_COLLECTOR_ROOTS_METHOD_NAME, Collections.singletonList(reference));
- return value == null ? null : new GcRootsPathsParser().parse(value);
+ IntegerValue limitValue = myDebugProcess.getVirtualMachineProxy().mirrorOf(limit);
+ Value value = callMethod(GARBAGE_COLLECTOR_ROOTS_METHOD_NAME, Arrays.asList(reference, limitValue));
+ return value == null ? null : GcRootsPathsParser.INSTANCE.parse(value);
}
@Override
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/UnexpectedValueFormatException.java b/java/debugger/impl/src/com/intellij/debugger/memory/agent/UnexpectedValueFormatException.java
new file mode 100644
index 000000000000..e479ab041ac5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/memory/agent/UnexpectedValueFormatException.java
@@ -0,0 +1,8 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.debugger.memory.agent;
+
+public class UnexpectedValueFormatException extends RuntimeException {
+ public UnexpectedValueFormatException(String message) {
+ super(message);
+ }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/BooleanParser.kt b/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/BooleanParser.kt
deleted file mode 100644
index 9ce79924d419..000000000000
--- a/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/BooleanParser.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
-package com.intellij.debugger.memory.agent.parsers
-
-import com.sun.jdi.BooleanValue
-import com.sun.jdi.Value
-
-object BooleanParser : ResultParser {
- override fun parse(value: Value): Boolean {
- return (value as? BooleanValue)?.value() ?: false
- }
-}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/GcRootsPathsParser.kt b/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/GcRootsPathsParser.kt
index dbad15f984c7..64a51e510726 100644
--- a/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/GcRootsPathsParser.kt
+++ b/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/GcRootsPathsParser.kt
@@ -1,62 +1,20 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.debugger.memory.agent.parsers
-import com.intellij.debugger.memory.agent.MemoryAgentReferringObjectProvider
import com.intellij.debugger.engine.ReferringObjectsProvider
-import com.intellij.openapi.diagnostic.Logger
+import com.intellij.debugger.memory.agent.MemoryAgentReferringObjectProvider
+import com.intellij.debugger.memory.agent.UnexpectedValueFormatException
import com.sun.jdi.ArrayReference
-import com.sun.jdi.IntegerValue
-import com.sun.jdi.ObjectReference
import com.sun.jdi.Value
-import java.util.ArrayList
-
-class GcRootsPathsParser : ResultParser {
- private companion object {
- val LOG = Logger.getInstance(GcRootsPathsParser::class.java)
- }
+object GcRootsPathsParser : ResultParser {
override fun parse(value: Value): ReferringObjectsProvider {
if (value is ArrayReference) {
- LOG.assertTrue(value.length() == 2, "Array must represent 2 values: objects and backward references")
- val values = parseValues(value.getValue(0))
- val backwardReferences = parseBackwardReferences(value.getValue(1))
+ if (value.length() != 2) throw UnexpectedValueFormatException("Array must represent 2 values: objects and backward references")
+ val values = ObjectReferencesParser.parse(value.getValue(0))
+ val backwardReferences = BackwardReferencesParser.parse(value.getValue(1))
return MemoryAgentReferringObjectProvider(values, backwardReferences)
}
- throw AssertionError("Incorrect result format: array of arrays is expected")
- }
-
- private fun parseBackwardReferences(value: Value): List> {
- if (value is ArrayReference) {
- val result = ArrayList>()
- for (item in value.values) {
- if (item !is ArrayReference || "int" == item.type().name()) {
- throw AssertionError("Incorrect result format: int array expected")
- }
- val ints = item.values.map { x -> (x as IntegerValue).value() }
- result.add(ints)
- }
-
- return result
- }
-
- throw AssertionError("Incorrect result format: array with nested int arrays expected")
- }
-
- private fun parseValues(value: Value): List {
- if (value is ArrayReference) {
- val result = ArrayList()
- for (item in value.values) {
- if (item !is ObjectReference) break
- result.add(item)
- }
-
- if (result.size != value.length()) {
- throw AssertionError("All values should be object references but some of them are not")
- }
-
- return result
- }
-
- throw AssertionError("Incorrect result format: array with object references expected")
+ throw UnexpectedValueFormatException("Array of arrays is expected")
}
}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/LongValueParser.kt b/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/LongValueParser.kt
deleted file mode 100644
index b6ec423d5baa..000000000000
--- a/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/LongValueParser.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
-package com.intellij.debugger.memory.agent.parsers
-
-import com.sun.jdi.PrimitiveValue
-import com.sun.jdi.Value
-
-class LongValueParser : ResultParser {
- override fun parse(value: Value): Long {
- if (value is PrimitiveValue) {
- return value.longValue()
- }
-
- throw IllegalArgumentException("Unexpected argument. Primitive value is expected")
- }
-}
\ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/Parsers.kt b/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/Parsers.kt
new file mode 100644
index 000000000000..ece5663b0498
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/Parsers.kt
@@ -0,0 +1,73 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.debugger.memory.agent.parsers
+
+import com.intellij.debugger.memory.agent.UnexpectedValueFormatException
+import com.sun.jdi.*
+import java.util.ArrayList
+
+object BooleanParser : ResultParser {
+ override fun parse(value: Value): Boolean {
+ return (value as? BooleanValue)?.value() ?: false
+ }
+}
+
+object LongValueParser : ResultParser {
+ override fun parse(value: Value): Long {
+ if (value is PrimitiveValue) {
+ return value.longValue()
+ }
+
+ throw UnexpectedValueFormatException("Primitive value is expected")
+ }
+}
+
+object ObjectReferencesParser : ResultParser> {
+ override fun parse(value: Value): List {
+ if (value is ArrayReference) {
+ val result = ArrayList()
+ for (item in value.values) {
+ if (item !is ObjectReference) break
+ result.add(item)
+ }
+
+ if (result.size != value.length()) {
+ throw UnexpectedValueFormatException(
+ "All values should be object references but some of them are not")
+ }
+
+ return result
+ }
+
+ throw UnexpectedValueFormatException("Array with object references expected")
+ }
+}
+
+object BackwardReferencesParser : ResultParser>> {
+ override fun parse(value: Value): List> {
+ if (value !is ArrayReference) throw UnexpectedValueFormatException("Array with nested arrays expected")
+
+ val result = ArrayList>()
+ for (linksInfo in value.values) {
+ if (linksInfo !is ArrayReference) throw UnexpectedValueFormatException("Object references information should be represented by array")
+ val indices = IntArrayParser.parse(linksInfo.getValue(0))
+ .distinct() // drop duplicates
+ .filter { it != -1 } // drop gc roots
+ // TODO: parse kinds and infos as well
+
+ result.add(indices)
+ }
+
+ return result
+ }
+}
+
+object IntArrayParser : ResultParser> {
+ override fun parse(value: Value): List {
+ if (value !is ArrayReference) throw UnexpectedValueFormatException("Array expected")
+ val items = value.values
+ if (items.isEmpty()) return emptyList()
+ if (items[0] !is IntegerValue) throw UnexpectedValueFormatException("array elements should be integers")
+ return items.map { it as IntegerValue }.map(IntegerValue::value)
+ }
+
+}
\ No newline at end of file