Initial: memory agent

This commit is contained in:
Vitaliy.Bibaev
2019-01-19 18:22:31 +03:00
parent 2c33597f30
commit c565ed3fac
16 changed files with 563 additions and 9 deletions
@@ -21,8 +21,8 @@
<orderEntry type="module" module-name="intellij.platform.ide.impl" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="module" module-name="intellij.platform.jps.build" />
<orderEntry type="library" name="sa-jdwp" level="project" />
<orderEntry type="module" module-name="intellij.java.debugger.memory.agent" />
<orderEntry type="library" name="sa-jdwp" level="project" />
</component>
<component name="copyright">
<Base>
@@ -8,6 +8,7 @@ import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.engine.ReferringObjectsProvider;
import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
@@ -27,22 +28,39 @@ import java.util.List;
public class JavaReferringObjectsValue extends JavaValue {
private static final long MAX_REFERRING = 100;
private final ReferringObjectsProvider myReferringObjectsProvider;
private final boolean myIsField;
private JavaReferringObjectsValue(@Nullable JavaValue parent,
@NotNull ValueDescriptorImpl valueDescriptor,
@NotNull EvaluationContextImpl evaluationContext,
@NotNull ReferringObjectsProvider referringObjectsProvider,
NodeManagerImpl nodeManager,
boolean isField) {
super(parent, valueDescriptor, evaluationContext, nodeManager, false);
myReferringObjectsProvider = referringObjectsProvider;
myIsField = isField;
}
public JavaReferringObjectsValue(@NotNull JavaValue javaValue, boolean isField) {
public JavaReferringObjectsValue(@NotNull JavaValue javaValue,
@NotNull ReferringObjectsProvider referringObjectsProvider,
boolean isField) {
super(null, javaValue.getName(), javaValue.getDescriptor(), javaValue.getEvaluationContext(), javaValue.getNodeManager(), false);
myReferringObjectsProvider = referringObjectsProvider;
myIsField = isField;
}
@Nullable
@Override
public XReferrersProvider getReferrersProvider() {
return new XReferrersProvider() {
@Override
public XValue getReferringObjectsValue() {
return new JavaReferringObjectsValue(JavaReferringObjectsValue.this, myReferringObjectsProvider, false);
}
};
}
@Override
public void computeChildren(@NotNull final XCompositeNode node) {
scheduleCommand(getEvaluationContext(), node, new SuspendContextCommandImpl(getEvaluationContext().getSuspendContext()) {
@@ -59,7 +77,7 @@ public class JavaReferringObjectsValue extends JavaValue {
List<ObjectReference> references;
try {
references = ((ObjectReference)value).referringObjects(MAX_REFERRING);
references = myReferringObjectsProvider.getReferringObjects((ObjectReference)value, MAX_REFERRING);
} catch (ObjectCollectedException e) {
node.setErrorMessage(DebuggerBundle.message("evaluation.error.object.collected"));
return;
@@ -76,7 +94,8 @@ public class JavaReferringObjectsValue extends JavaValue {
return reference;
}
};
children.add(new JavaReferringObjectsValue(null, descriptor, getEvaluationContext(), getNodeManager(), true));
children.add(new JavaReferringObjectsValue(null, descriptor, getEvaluationContext(),
myReferringObjectsProvider, getNodeManager(), true));
i++;
}
else {
@@ -96,7 +115,8 @@ public class JavaReferringObjectsValue extends JavaValue {
return null;
}
};
children.add("Referrer " + i++, new JavaReferringObjectsValue(null, descriptor, getEvaluationContext(), getNodeManager(), false));
children.add("Referrer " + i++, new JavaReferringObjectsValue(null, descriptor, getEvaluationContext(),
myReferringObjectsProvider, getNodeManager(), false));
}
}
@@ -650,7 +650,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
return new XReferrersProvider() {
@Override
public XValue getReferringObjectsValue() {
return new JavaReferringObjectsValue(JavaValue.this, false);
return new JavaReferringObjectsValue(JavaValue.this, ReferringObjectsProvider.BASIC_JDI, false);
}
};
}
@@ -0,0 +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.engine;
import com.sun.jdi.ObjectReference;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public interface ReferringObjectsProvider {
@NotNull
List<ObjectReference> getReferringObjects(@NotNull ObjectReference value, long limit);
ReferringObjectsProvider BASIC_JDI = new ReferringObjectsProvider() {
@NotNull
@Override
public List<ObjectReference> getReferringObjects(@NotNull ObjectReference value, long limit) {
return value.referringObjects(limit);
}
};
}
@@ -0,0 +1,29 @@
// Copyright 2000-2018 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.action;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.memory.agent.AgentLoader;
import com.intellij.debugger.memory.agent.MemoryAgent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.messages.MessageDialog;
import com.intellij.util.ArrayUtil;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import com.sun.jdi.ObjectReference;
import org.jetbrains.annotations.NotNull;
/**
* @author Vitaliy.Bibaev
*/
public class CalculateRetainedSizeAction extends NativeAgentActionBase {
@Override
protected void perform(@NotNull EvaluationContextImpl evaluationContext,
@NotNull ObjectReference reference,
@NotNull XValueNodeImpl node) {
MemoryAgent memoryAgent = new AgentLoader().load(evaluationContext, evaluationContext.getDebugProcess().getVirtualMachineProxy());
long size = memoryAgent.evaluateObjectSize(reference);
ApplicationManager.getApplication().invokeLater(
() -> new MessageDialog(node.getTree().getProject(), String.valueOf(size), "Size of the Object",
ArrayUtil.EMPTY_STRING_ARRAY, 0, null, false)
.show());
}
}
@@ -0,0 +1,65 @@
// Copyright 2000-2018 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.action;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.JavaValue;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.managerThread.DebuggerCommand;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;
import com.intellij.xdebugger.frame.XSuspendContext;
import com.intellij.xdebugger.frame.XValue;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.Value;
import org.jetbrains.annotations.NotNull;
public abstract class NativeAgentActionBase extends DebuggerTreeAction {
protected final Logger LOG = Logger.getInstance(this.getClass());
@Override
protected void perform(XValueNodeImpl node, @NotNull String nodeName, AnActionEvent e) {
Project project = node.getTree().getProject();
XValue container = node.getValueContainer();
XDebugSession currentSession = XDebuggerManager.getInstance(project).getCurrentSession();
XSuspendContext suspendContext = currentSession != null ? currentSession.getSuspendContext() : null;
DebugProcessImpl debugProcess =
suspendContext instanceof SuspendContextImpl ? ((SuspendContextImpl)suspendContext).getDebugProcess() : null;
if (debugProcess == null) return;
debugProcess.getManagerThread().invokeCommand(new DebuggerCommand() {
@Override
public void action() {
if (container instanceof JavaValue) {
EvaluationContextImpl evaluationContext = debugProcess.getDebuggerContext().createEvaluationContext();
if (evaluationContext == null) return;
Value value = ((JavaValue)container).getDescriptor().getValue();
perform(evaluationContext, (ObjectReference)value, node);
}
}
@Override
public void commandCancelled() {
LOG.info("command cancelled");
}
});
}
@Override
protected boolean isEnabled(@NotNull XValueNodeImpl node, @NotNull AnActionEvent e) {
if (!super.isEnabled(node, e)) return false;
XValue container = node.getValueContainer();
if (container instanceof JavaValue) {
if (((JavaValue)container).getDescriptor().getValue() instanceof ObjectReference) return true;
}
return false;
}
protected abstract void perform(@NotNull EvaluationContextImpl evaluationContext,
@NotNull ObjectReference reference,
@NotNull XValueNodeImpl node);
}
@@ -0,0 +1,47 @@
// Copyright 2000-2018 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.action;
import com.intellij.debugger.actions.JavaReferringObjectsValue;
import com.intellij.debugger.engine.JavaValue;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.debugger.memory.agent.AgentLoader;
import com.intellij.debugger.memory.agent.MemoryAgent;
import com.intellij.debugger.engine.ReferringObjectsProvider;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.xdebugger.impl.XDebuggerManagerImpl;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.tree.XInspectDialog;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import com.sun.jdi.ObjectReference;
import org.jetbrains.annotations.NotNull;
public class ShowGarbageCollectorRootsAction extends NativeAgentActionBase {
@Override
protected void perform(@NotNull EvaluationContextImpl evaluationContext,
@NotNull ObjectReference reference,
@NotNull XValueNodeImpl node) {
VirtualMachineProxyImpl virtualMachineProxy = evaluationContext.getDebugProcess().getVirtualMachineProxy();
MemoryAgent memoryAgent = new AgentLoader().load(evaluationContext, virtualMachineProxy);
ReferringObjectsProvider roots = memoryAgent.canFindGcRoots() ? memoryAgent.findGcRoots(reference) : null;
if (roots == null) {
XDebuggerManagerImpl.NOTIFICATION_GROUP.createNotification("This feature is unavailable", NotificationType.INFORMATION);
return;
}
ApplicationManager.getApplication().invokeLater(
() -> {
XDebuggerTree tree = node.getTree();
JavaValue javaValue = (JavaValue)node.getValueContainer();
JavaReferringObjectsValue value = new JavaReferringObjectsValue(javaValue, roots, false);
XInspectDialog dialog =
new XInspectDialog(tree.getProject(), tree.getEditorsProvider(), tree.getSourcePosition(), StringUtil.notNullize(node.getName()),
value, tree.getValueMarkers(),
evaluationContext.getDebugProcess().getSession().getXDebugSession(), false);
dialog.setTitle("Paths to GC Roots");
dialog.show();
}
);
}
}
@@ -0,0 +1,102 @@
// Copyright 2000-2018 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;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
import com.intellij.debugger.engine.ReferringObjectsProvider;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.jdi.VirtualMachineProxy;
import com.intellij.debugger.impl.ClassLoadingUtils;
import com.intellij.openapi.diagnostic.Logger;
import com.sun.jdi.ClassLoaderReference;
import com.sun.jdi.ClassType;
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 class AgentLoader {
private static final Logger LOG = Logger.getInstance(AgentLoader.class);
private static final MemoryAgent DEFAULT_PROXY = new MyDisabledMemoryAgent();
@NotNull
public MemoryAgent load(@NotNull EvaluationContextImpl evaluationContext, @NotNull VirtualMachineProxy virtualMachine) {
DebuggerManagerThreadImpl.assertIsManagerThread();
try {
ClassType classType = ensureClassLoaded(evaluationContext, virtualMachine);
return classType == null ? DEFAULT_PROXY : new MemoryAgentImpl(evaluationContext, classType);
}
catch (EvaluateException e) {
LOG.error("Could not load proxy class", e);
return DEFAULT_PROXY;
}
}
@Nullable
private static ClassType ensureClassLoaded(@NotNull EvaluationContextImpl context, @NotNull VirtualMachineProxy vm)
throws EvaluateException {
List<ReferenceType> classes = vm.classesByName(MemoryAgentImpl.PROXY_CLASS_NAME);
if (classes.isEmpty()) {
ClassType classType = loadUtilityClass(context);
if (classType == null) {
LOG.error("Could not load proxy class");
}
return classType;
}
LOG.assertTrue(classes.size() == 1, "Too many utility classes loaded: " + classes.size());
return (ClassType)classes.get(0);
}
@Nullable
private static ClassType loadUtilityClass(@NotNull EvaluationContextImpl context) throws EvaluateException {
DebugProcessImpl debugProcess = context.getDebugProcess();
byte[] bytes = readUtilityClass();
ClassLoaderReference classLoader = ClassLoadingUtils.getClassLoader(context, debugProcess);
ClassLoadingUtils.defineClass(MemoryAgentImpl.PROXY_CLASS_NAME, bytes, context, debugProcess, classLoader);
return (ClassType)debugProcess.findClass(context, MemoryAgentImpl.PROXY_CLASS_NAME, classLoader);
}
@NotNull
private static byte[] readUtilityClass() {
return new ProxyExtractor().extractProxy();
}
private static class MyDisabledMemoryAgent implements MemoryAgent {
@Override
public boolean canEvaluateObjectSize() {
return false;
}
@Override
public long evaluateObjectSize(@NotNull ObjectReference reference) {
throw new UnsupportedOperationException();
}
@Override
public boolean canEvaluateObjectsSizes() {
return false;
}
@Override
public List<Long> evaluateObjectsSizes(@NotNull List<ObjectReference> references) {
throw new UnsupportedOperationException();
}
@Override
public boolean canFindGcRoots() {
return false;
}
@Override
public ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference) {
throw new UnsupportedOperationException();
}
}
}
@@ -0,0 +1,24 @@
// Copyright 2000-2018 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;
import com.intellij.debugger.engine.ReferringObjectsProvider;
import com.sun.jdi.ObjectReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface MemoryAgent {
boolean canEvaluateObjectSize();
long evaluateObjectSize(@NotNull ObjectReference reference);
boolean canEvaluateObjectsSizes();
List<Long> evaluateObjectsSizes(@NotNull List<ObjectReference> references);
boolean canFindGcRoots();
@Nullable
ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference);
}
@@ -0,0 +1,106 @@
// Copyright 2000-2018 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;
import com.intellij.debugger.engine.ReferringObjectsProvider;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
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.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public class MemoryAgentImpl implements MemoryAgent {
public static final String PROXY_CLASS_NAME = "com.intellij.memory.agent.proxy.IdeaNativeAgentProxy";
private static final Logger LOG = Logger.getInstance(MemoryAgentImpl.class);
private static final String SIZE_OF_SINGLE_OBJECT_METHOD_NAME = "size";
private static final String SIZE_OF_OBJECTS_METHOD_NAME = "size";
private static final String GARBAGE_COLLECTOR_ROOTS_METHOD_NAME = "gcRoots";
private final EvaluationContextImpl myEvaluationContext;
private final ClassType myProxyClassType;
public MemoryAgentImpl(@NotNull EvaluationContextImpl context, @NotNull ClassType reference) {
myEvaluationContext = context;
myProxyClassType = reference;
}
@Override
public boolean canEvaluateObjectSize() {
return !myProxyClassType.methodsByName(SIZE_OF_SINGLE_OBJECT_METHOD_NAME).isEmpty();
}
@Override
public long evaluateObjectSize(@NotNull ObjectReference reference) {
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;
}
@Override
public boolean canEvaluateObjectsSizes() {
return !myProxyClassType.methodsByName(SIZE_OF_OBJECTS_METHOD_NAME).isEmpty();
}
@Override
public List<Long> evaluateObjectsSizes(@NotNull List<ObjectReference> references) {
if (!canEvaluateObjectsSizes()) throw new UnsupportedOperationException();
Value result = callMethod(SIZE_OF_OBJECTS_METHOD_NAME, references);
// TODO: Implement method and conversion
return Collections.emptyList();
}
@Override
public boolean canFindGcRoots() {
return !myProxyClassType.methodsByName(GARBAGE_COLLECTOR_ROOTS_METHOD_NAME).isEmpty();
}
@Nullable
@Override
public ReferringObjectsProvider findGcRoots(@NotNull ObjectReference reference) {
if (!canFindGcRoots()) throw new UnsupportedOperationException();
Value value = callMethod(GARBAGE_COLLECTOR_ROOTS_METHOD_NAME, Collections.singletonList(reference));
return value == null ? null : new GcRootsPathsParser().parse(value);
}
@Nullable
private Value callMethod(@NotNull String methodName,
@NotNull List<? extends Value> args) {
List<Method> methods = myProxyClassType.methodsByName(methodName);
if (methods.isEmpty()) {
LOG.error("Method \"" + methodName + "\" not found");
return null;
}
if (methods.size() > 1) {
LOG.warn("Too many methods \"" + methodName + "\" found. Count: " + methods.size());
}
Method method = methods.get(0);
if (!method.isStatic()) {
LOG.error("Utility method should be static");
}
try {
return myEvaluationContext.getDebugProcess().invokeMethod(myEvaluationContext, myProxyClassType, method, args);
}
catch (EvaluateException e) {
LOG.error("Something went wrong", e);
}
return null;
}
private static long parseLong(@Nullable Value value) {
if (value instanceof PrimitiveValue) {
return ((PrimitiveValue)value).longValue();
}
throw new IllegalArgumentException("Unexpected argument. Primitive value is expected");
}
}
@@ -0,0 +1,42 @@
// Copyright 2000-2018 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;
import com.intellij.debugger.engine.ReferringObjectsProvider;
import com.intellij.openapi.diagnostic.Logger;
import com.sun.jdi.ObjectReference;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class MemoryAgentReferringObjectProvider implements ReferringObjectsProvider {
private static final Logger LOG = Logger.getInstance(MemoryAgentReferringObjectProvider.class);
private final Map<ObjectReference, Integer> myReversedMap = new HashMap<>();
private final List<ObjectReference> myDirectMap;
private final List<List<Integer>> myPaths;
public MemoryAgentReferringObjectProvider(@NotNull List<ObjectReference> values, @NotNull List<List<Integer>> paths) {
myDirectMap = values;
for (int i = 0; i < values.size(); i++) {
myReversedMap.put(values.get(i), i);
}
myPaths = paths;
}
@NotNull
@Override
public List<ObjectReference> getReferringObjects(@NotNull ObjectReference value, long limit) {
Integer index = myReversedMap.get(value);
if (index == null) {
LOG.error("Could not find referring object for reference " + value.toString());
return Collections.emptyList();
}
return myPaths.get(index).stream().limit(limit).map(ix -> myDirectMap.get(ix)).collect(Collectors.toList());
}
}
@@ -0,0 +1,62 @@
// 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.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<ReferringObjectsProvider> {
private companion object {
val LOG = Logger.getInstance(GcRootsPathsParser::class.java)
}
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))
return MemoryAgentReferringObjectProvider(values, backwardReferences)
}
throw AssertionError("Incorrect result format: array of arrays is expected")
}
private fun parseBackwardReferences(value: Value): List<List<Int>> {
if (value is ArrayReference) {
val result = ArrayList<List<Int>>()
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<ObjectReference> {
if (value is ArrayReference) {
val result = ArrayList<ObjectReference>()
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")
}
}
@@ -0,0 +1,15 @@
// 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<Long> {
override fun parse(value: Value): Long {
if (value is PrimitiveValue) {
return value.longValue()
}
throw IllegalArgumentException("Unexpected argument. Primitive value is expected")
}
}
@@ -0,0 +1,9 @@
// 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.Value;
import org.jetbrains.annotations.NotNull;
public interface ResultParser<T> {
T parse(@NotNull Value value);
}
@@ -4,13 +4,12 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="library" name="debugger-memory-agent" level="project" />
<orderEntry type="library" name="commons-io" level="project" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="library" name="kotlin-stdlib-jdk8" level="project" />
</component>
</module>
+14
View File
@@ -250,6 +250,20 @@
relative-to-action="Debugger.ShowReferring"/>
</action>
<action class="com.intellij.debugger.memory.action.CalculateRetainedSizeAction"
id="Memory.CalculateRetainedSize"
text="Calculate Retained Size">
<add-to-group group-id="XDebugger.ValueGroup" anchor="after"
relative-to-action="MemoryView.ShowInstancesFromDebuggerTree"/>
</action>
<action class="com.intellij.debugger.memory.action.ShowGarbageCollectorRootsAction"
id="Memory.ShowGarbageCollectorRoots"
text="Find Garbage Collector Roots">
<add-to-group group-id="XDebugger.ValueGroup" anchor="after"
relative-to-action="Memory.CalculateRetainedSize"/>
</action>
<action class="com.intellij.debugger.memory.action.tracking.JumpToAllocationSourceAction"
id="MemoryView.ShowAllocationStackTrace"
text="Jump To Allocation Position">