Skip to content

Commit

Permalink
Bug 581644 - Allow stack frames as pseudo-objects for HPROF snapshots
Browse files Browse the repository at this point in the history
Initial code drop, including common name resolver for DTFJ and HPROF
stack frames.

Change-Id: I6ba5ddaafed610b7501856bc24dfd21e787e137c
  • Loading branch information
ajohnson1 committed Mar 22, 2023
1 parent 47a32ec commit 0c72944
Show file tree
Hide file tree
Showing 22 changed files with 825 additions and 87 deletions.
3 changes: 3 additions & 0 deletions plugins/org.eclipse.mat.api/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@

<!-- Wildfly / JBoss Enterprise Application Platform -->
<resolver impl="org.eclipse.mat.inspections.wildfly.WildflyJbossNameResolvers$ModuleClassLoaderResolver"/>

<!-- stacks as pseudo-objects -->
<resolver impl="org.eclipse.mat.inspections.threads.StackFrameResolver"/>
</extension>

<extension point="org.eclipse.mat.api.requestResolver">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (c) 2023 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Andrew Johnson - initial API and implementation
*******************************************************************************/
package org.eclipse.mat.inspections.threads;

import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.internal.Messages;
import org.eclipse.mat.snapshot.extension.IClassSpecificNameResolver;
import org.eclipse.mat.snapshot.extension.Subjects;
import org.eclipse.mat.snapshot.model.IObject;
import org.eclipse.mat.util.MessageUtil;

@Subjects({"<method>", "<stack frame>"})
public class StackFrameResolver implements IClassSpecificNameResolver
{

public StackFrameResolver()
{}

public String resolve(IObject object) throws SnapshotException
{
String methodName = (String) object.resolveValue("methodName");
String fileName = (String) object.resolveValue("fileName");
if (fileName == null)
fileName = (String) object.getClazz().resolveValue("fileName");
Integer lineNumber = (Integer) object.resolveValue("lineNumber");
Integer compLevel = (Integer) object.resolveValue("compilationLevel");
Boolean nativ = (Boolean) object.resolveValue("native");
String ret;
if (fileName != null && lineNumber != null && lineNumber > 0)
{
if (methodName == null)
if (Boolean.TRUE.equals(nativ))
ret = MessageUtil.format(Messages.StackFrameResolver_file_line_native, fileName, lineNumber);
else if (compLevel != null && compLevel > 0)
ret = MessageUtil.format(Messages.StackFrameResolver_file_line_compiled, fileName, lineNumber);
else
ret = MessageUtil.format(Messages.StackFrameResolver_file_line, fileName, lineNumber);
else
if (Boolean.TRUE.equals(nativ))
ret = MessageUtil.format(Messages.StackFrameResolver_method_file_line_native, methodName, fileName, lineNumber);
else if (compLevel != null && compLevel > 0)
ret = MessageUtil.format(Messages.StackFrameResolver_method_file_line_compiled, methodName, fileName, lineNumber);
else
ret = MessageUtil.format(Messages.StackFrameResolver_method_file_line, methodName, fileName, lineNumber);
}
else if (fileName != null) {
if (methodName == null)
if (Boolean.TRUE.equals(nativ))
ret = MessageUtil.format(Messages.StackFrameResolver_file_native, fileName);
else if (compLevel != null && compLevel > 0)
ret = MessageUtil.format(Messages.StackFrameResolver_file_compiled, fileName);
else
ret = MessageUtil.format(Messages.StackFrameResolver_file, fileName);
else
if (Boolean.TRUE.equals(nativ))
ret = MessageUtil.format(Messages.StackFrameResolver_method_file_native, methodName, fileName);
else if (compLevel != null && compLevel > 0)
ret = MessageUtil.format(Messages.StackFrameResolver_method_file_compiled, methodName, fileName);
else
ret = MessageUtil.format(Messages.StackFrameResolver_method_file, methodName, fileName);
} else if (methodName != null) {
ret = MessageUtil.format(Messages.StackFrameResolver_method, methodName);
} else {
ret = ""; //$NON-NLS-1$
}
return ret;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2021 SAP AG, IBM Corporation and others.
* Copyright (c) 2008, 2023 SAP AG, IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -566,7 +566,11 @@ public int[] getObjectIds()
int[] objectIds = frame.getLocalObjectsIds();
SetInt si = new SetInt();
for (int i : objectIds)
si.add(i);
{
// Ignore stack frame psuedo-objects
if (!(i == getObjectId() && !snapshot.isClass(i)))
si.add(i);
}
return si.toArray();
}

Expand Down Expand Up @@ -659,8 +663,18 @@ else if (row instanceof ThreadStackFrameNode)
}
}
}
List<NamedReference> refs = threadInfo
.getThreadObject().getOutboundReferences();
/*
* Handle references from the thread
* or the stack frame pseudo-object.
*/
int refererId = tsfmln.threadStackFrameNode.objectId;
IObject refererObj;
if (refererId != -1 && !snapshot.isClass(refererId))
// Actual stack frame pseudo object
refererObj = snapshot.getObject(refererId);
else
refererObj = threadInfo.getThreadObject();
List<NamedReference> refs = refererObj.getOutboundReferences();
for (NamedReference ref : refs)
{
if (ref.getObjectId() != objectId)
Expand All @@ -676,6 +690,7 @@ else if (row instanceof ThreadStackFrameNode)
: Messages.ThreadStackQuery_Label_Local_Busy_Monitor;
}
}
return tlr.getName();
}
}
}
Expand Down Expand Up @@ -773,7 +788,7 @@ public List<?> getChildren(Object parent)
tsfn.objectId = frameIds[tsfn.depth];
if (tsfn.objectId == -1)
{
// Add the class from the class name of the stack frame
// Add the class from the method name or class name of the stack frame
tsfn.objectId = frameId(frame);
}
stackFrameNodes.add(tsfn);
Expand All @@ -790,6 +805,9 @@ else if (parent instanceof ThreadStackFrameNode)
List<ThreadStackFrameLocalNode> stackFrameLocals = new ArrayList<ThreadStackFrameLocalNode>(localIds.length);
for (int localId : localIds)
{
// Is the local actually just the stack frame object (and not the class)?
if (tsfn.objectId == localId && !snapshot.isClass(localId))
continue;
ThreadStackFrameLocalNode tsfln = new ThreadStackFrameLocalNode();
tsfln.objectId = localId;
tsfln.threadStackFrameNode = tsfn;
Expand Down Expand Up @@ -835,7 +853,24 @@ private int[] frameIds(ThreadOverviewNode ton)
int f = (Integer)fn;
if (f >= 0 && f < numFrames)
{
frameIds[f] = tlr.getObjectId();
frameIds[f] = tlr.getObjectId();
break;
}
}
/*
* See if a reference from the thread is to
* the pseudo-object stack frame
*/
for (int f = 0; f < ton.stack.getStackFrames().length; ++f)
{
IStackFrame fm = ton.stack.getStackFrames()[f];
for (int o : fm.getLocalObjectsIds())
{
if (o == tlr.getObjectId())
{
frameIds[f] = o;
break;
}
}
}
}
Expand All @@ -852,20 +887,39 @@ private int[] frameIds(ThreadOverviewNode ton)

/**
* Return the id of the class associated with this stack frame.
* @param frm
* @param frm the stack frame
* @return the id, or -1 if not found
*/
private int frameId(IStackFrame frm)
{
String fm = frm.getText();
if (fm != null)
{
// Extract the full method name.
// Example text:
// at package.name.Classname.method(Arguments)LReturnCls; Classname.java(13)
String fm1 = fm.replaceFirst("\\s*at\\s+([^ ]+).*", "$1"); //$NON-NLS-1$//$NON-NLS-2$
try
{
Collection<IClass>clss = snapshot.getClassesByName(fm1, false);
// If unambiguous which class
if (clss != null && clss.size() == 1)
{
for (IClass cls : clss)
{
return cls.getObjectId();
}
}
}
catch (SnapshotException e)
{
}
// Extract the class name from the full method name
// at package.name.Classname.method(Arguments) Classname.java(13)
fm = fm.replaceFirst("\\s*at\\s+([^(]+)\\.[^.(]+.*", "$1"); //$NON-NLS-1$//$NON-NLS-2$
// at package.name.Classname.method(Arguments)LReturnCls; Classname.java(13)
fm1 = fm.replaceFirst("\\s*at\\s+([^(]+)\\.[^.(]+.*", "$1"); //$NON-NLS-1$//$NON-NLS-2$
try
{
Collection<IClass>clss = snapshot.getClassesByName(fm, false);
Collection<IClass>clss = snapshot.getClassesByName(fm1, false);
// If unambiguous which class
if (clss != null && clss.size() == 1)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2022 SAP AG and IBM Corporation.
* Copyright (c) 2008, 2023 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -577,6 +577,23 @@ public class Messages extends NLS
public static String SoftReferenceStatQuery_Label_Retained;
public static String SoftReferenceStatQuery_Label_StronglyRetainedReferents;

public static String StackFrameResolver_file;
public static String StackFrameResolver_file_compiled;
public static String StackFrameResolver_file_native;
public static String StackFrameResolver_file_line;
public static String StackFrameResolver_file_line_compiled;
public static String StackFrameResolver_file_line_native;
public static String StackFrameResolver_method;
public static String StackFrameResolver_method_compiled;
public static String StackFrameResolver_method_native;
public static String StackFrameResolver_method_file;
public static String StackFrameResolver_method_file_compiled;
public static String StackFrameResolver_method_file_native;
public static String StackFrameResolver_method_file_line;
public static String StackFrameResolver_method_file_line_compiled;
public static String StackFrameResolver_method_file_line_native;

public static String SubjectRegistry_DuplicateResolver;
public static String SubjectRegistry_Error_MissingAnnotation;
public static String SubjectRegistry_ErrorMsg_MissingSubjectAnnotation;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
###############################################################################
# Copyright (c) 2008, 2022 SAP AG and IBM Corporation.
# Copyright (c) 2008, 2023 SAP AG and IBM Corporation.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
# which accompanies this distribution, and is available at
Expand Down Expand Up @@ -512,6 +512,22 @@ SnapshotQuery_ErrorMsg_UnsupportedTyp=Unsupported type for argument {0}: {1}\n(U
SoftReferenceStatQuery_Label_Referenced=Histogram of Softly Referenced
SoftReferenceStatQuery_Label_Retained=Only Softly Retained
SoftReferenceStatQuery_Label_StronglyRetainedReferents=Referents strongly retained by soft reference
StackFrameResolver_file=({0})
StackFrameResolver_file_compiled=({0}(Compiled Code))
StackFrameResolver_file_native=({0}(Native Method}))
StackFrameResolver_file_line=({0}:{1})
StackFrameResolver_file_line_compiled=({0}:{1}(Compiled Code}))
StackFrameResolver_file_line_native=({0}:{1}(Native Method}))
StackFrameResolver_method={0}
StackFrameResolver_method_compiled={0} ((Compiled Code))
StackFrameResolver_method_native={0} ((Native Method))
StackFrameResolver_method_file={0} ({1})
StackFrameResolver_method_file_compiled={0} ({1}(Compiled Code))
StackFrameResolver_method_file_native={0} ({1}(Native Method))
StackFrameResolver_method_file_line={0} ({1}:{2})
StackFrameResolver_method_file_line_compiled={0} ({1}:{2}(Compiled Code))
StackFrameResolver_method_file_line_native={0} ({1}:{2}(Native Method))
SubjectRegistry_DuplicateResolver=Duplicate subject name resolver for {0}, {1} replaced by {2}
SubjectRegistry_Error_MissingAnnotation=Missing or empty @Subject(s) annotation: ''{0}''
SubjectRegistry_ErrorMsg_MissingSubjectAnnotation=Missing or empty @Subject(s) annotation: ''{0}''
TaskInfo_Column_Id=Id
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2013 SAP AG, IBM Corporation and others.
* Copyright (c) 2008, 2023 SAP AG, IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -18,6 +18,7 @@
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.internal.MATPlugin;
import org.eclipse.mat.snapshot.ISnapshot;

Expand Down Expand Up @@ -131,7 +132,17 @@ else if (snapshot.isClass(objectId))
else if (snapshot.isClassLoader(objectId))
return isGCRoot ? CLASSLOADER_INSTANCE_AS_GC_ROOT : CLASSLOADER_INSTANCE;
else
{
try
{
if (snapshot.getClassOf(objectId).doesExtend("<stack frame>")
|| snapshot.getClassOf(objectId).doesExtend("<method>"))
return STACK_FRAME;
}
catch (SnapshotException e)
{}
return isGCRoot ? OBJECT_INSTANCE_AS_GC_ROOT : OBJECT_INSTANCE;
}
}

/**
Expand All @@ -152,7 +163,17 @@ else if (snapshot.isClass(objectId))
else if (snapshot.isClassLoader(objectId))
return isGCRoot ? CLASSLOADER_INSTANCE_IN_GC : CLASSLOADER_INSTANCE_IN;
else
{
try
{
if (snapshot.getClassOf(objectId).doesExtend("<stack frame>")
|| snapshot.getClassOf(objectId).doesExtend("<method>"))
return STACK_FRAME;
}
catch (SnapshotException e)
{}
return isGCRoot ? OBJECT_INSTANCE_IN_GC : OBJECT_INSTANCE_IN;
}
}

/**
Expand All @@ -173,7 +194,17 @@ else if (snapshot.isClass(objectId))
else if (snapshot.isClassLoader(objectId))
return isGCRoot ? CLASSLOADER_INSTANCE_OUT_GC : CLASSLOADER_INSTANCE_OUT;
else
{
try
{
if (snapshot.getClassOf(objectId).doesExtend("<stack frame>")
|| snapshot.getClassOf(objectId).doesExtend("<method>"))
return STACK_FRAME;
}
catch (SnapshotException e)
{}
return isGCRoot ? OBJECT_INSTANCE_OUT_GC : OBJECT_INSTANCE_OUT;
}
}

// this class must not have any dependency on AWT or SWT to be able to run
Expand All @@ -199,6 +230,8 @@ else if (snapshot.isClassLoader(objectId))
private static final URL CLASSLOADER_INSTANCE_OUT = build("out/classloader_obj");
private static final URL CLASSLOADER_INSTANCE_OUT_GC = build("out/classloader_obj_gc_root");

private static final URL STACK_FRAME = getURL("stack_frame.gif");

private static URL build(String name)
{
MATPlugin plugin = MATPlugin.getDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,19 @@ public final D createDelegate(IConfigurationElement configElement) throws CoreEx
if (subjects != null && subjects.length > 0)
{
for (int ii = 0; ii < subjects.length; ii++)
{
D oldResolver = resolvers.get(subjects[ii]);
if (oldResolver != null)
{
Logger.getLogger(getClass().getName()).log(
Level.WARNING,
MessageUtil.format(Messages.SubjectRegistry_DuplicateResolver,
subjects[ii],
oldResolver.getClass().getName(),
resolver.getClass().getName()));
}
resolvers.put(subjects[ii], resolver);
}
}
else
{
Expand Down

0 comments on commit 0c72944

Please sign in to comment.