From 4d7cacbf010f8ed4ae96702b1780e8ac61ed2655 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Thu, 31 Jan 2019 15:06:30 +0300 Subject: [PATCH] [memory-agent] Update version: 0.0.7 and integrate new data format --- .idea/libraries/debugger_memory_agent.xml | 6 +- .../ShowGarbageCollectorRootsAction.java | 3 +- .../debugger/memory/agent/AgentLoader.java | 2 +- .../debugger/memory/agent/MemoryAgent.java | 2 +- .../memory/agent/MemoryAgentImpl.java | 15 ++-- .../agent/UnexpectedValueFormatException.java | 8 ++ .../memory/agent/parsers/BooleanParser.kt | 11 --- .../agent/parsers/GcRootsPathsParser.kt | 56 ++------------ .../memory/agent/parsers/LongValueParser.kt | 15 ---- .../debugger/memory/agent/parsers/Parsers.kt | 73 +++++++++++++++++++ 10 files changed, 102 insertions(+), 89 deletions(-) create mode 100644 java/debugger/impl/src/com/intellij/debugger/memory/agent/UnexpectedValueFormatException.java delete mode 100644 java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/BooleanParser.kt delete mode 100644 java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/LongValueParser.kt create mode 100644 java/debugger/impl/src/com/intellij/debugger/memory/agent/parsers/Parsers.kt 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